@@ -106,89 +106,131 @@ protected List<Bookmark> GetBookmarksFromPath(string placesPath)
106106 }
107107
108108 private void LoadFaviconsFromDb ( string faviconDbPath , List < Bookmark > bookmarks )
109+ {
110+ try
109111 {
110- try
111- {
112- // Use a copy to avoid lock issues with the original file
113- var tempDbPath = Path . Combine ( _faviconCacheDir , $ "tempfavicons_{ Guid . NewGuid ( ) } .sqlite") ;
114- File . Copy ( faviconDbPath , tempDbPath , true ) ;
112+ // Use a copy to avoid lock issues with the original file
113+ var tempDbPath = Path . Combine ( _faviconCacheDir , $ "tempfavicons_{ Guid . NewGuid ( ) } .sqlite") ;
114+ File . Copy ( faviconDbPath , tempDbPath , true ) ;
115115
116- string dbPath = string . Format ( DbPathFormat , tempDbPath ) ;
117- using var connection = new SqliteConnection ( dbPath ) ;
118- connection . Open ( ) ;
116+ string dbPath = string . Format ( DbPathFormat , tempDbPath ) ;
117+ using var connection = new SqliteConnection ( dbPath ) ;
118+ connection . Open ( ) ;
119119
120- // Get favicons based on bookmark URLs
121- foreach ( var bookmark in bookmarks )
120+ // Get favicons based on bookmark URLs
121+ foreach ( var bookmark in bookmarks )
122+ {
123+ try
122124 {
123- try
124- {
125- if ( string . IsNullOrEmpty ( bookmark . Url ) )
126- continue ;
125+ if ( string . IsNullOrEmpty ( bookmark . Url ) )
126+ continue ;
127127
128- // Extract domain from URL
129- if ( ! Uri . TryCreate ( bookmark . Url , UriKind . Absolute , out Uri uri ) )
130- continue ;
128+ // Extract domain from URL
129+ if ( ! Uri . TryCreate ( bookmark . Url , UriKind . Absolute , out Uri uri ) )
130+ continue ;
131131
132- var domain = uri . Host ;
132+ var domain = uri . Host ;
133133
134- // Query for latest Firefox version favicon structure
135- using var cmd = connection . CreateCommand ( ) ;
136- cmd . CommandText = @"
137- SELECT i.data
138- FROM moz_icons i
139- JOIN moz_icons_to_pages ip ON i.id = ip.icon_id
140- JOIN moz_pages_w_icons p ON ip.page_id = p.id
141- WHERE p.page_url LIKE @url
142- AND i.data IS NOT NULL
143- ORDER BY i.width DESC -- Select largest icon available
144- LIMIT 1" ;
134+ // Query for latest Firefox version favicon structure
135+ using var cmd = connection . CreateCommand ( ) ;
136+ cmd . CommandText = @"
137+ SELECT i.data
138+ FROM moz_icons i
139+ JOIN moz_icons_to_pages ip ON i.id = ip.icon_id
140+ JOIN moz_pages_w_icons p ON ip.page_id = p.id
141+ WHERE p.page_url LIKE @url
142+ AND i.data IS NOT NULL
143+ ORDER BY i.width DESC -- Select largest icon available
144+ LIMIT 1" ;
145145
146- cmd . Parameters . AddWithValue ( "@url" , $ "%{ domain } %") ;
146+ cmd . Parameters . AddWithValue ( "@url" , $ "%{ domain } %") ;
147147
148- using var reader = cmd . ExecuteReader ( ) ;
149- if ( ! reader . Read ( ) || reader . IsDBNull ( 0 ) )
150- continue ;
148+ using var reader = cmd . ExecuteReader ( ) ;
149+ if ( ! reader . Read ( ) || reader . IsDBNull ( 0 ) )
150+ continue ;
151151
152- var imageData = ( byte [ ] ) reader [ "data" ] ;
152+ var imageData = ( byte [ ] ) reader [ "data" ] ;
153153
154- if ( imageData is not { Length : > 0 } )
155- continue ;
154+ if ( imageData is not { Length : > 0 } )
155+ continue ;
156156
157- var ext = IsSvgData ( imageData ) ? "svg" : "png" ;
158- var faviconPath = Path . Combine ( _faviconCacheDir , $ "firefox_{ domain } .{ ext } ") ;
157+ var faviconPath = Path . Combine ( _faviconCacheDir , $ "firefox_{ domain } .png") ;
159158
160- if ( ! File . Exists ( faviconPath ) )
159+ if ( ! File . Exists ( faviconPath ) )
160+ {
161+ if ( IsSvgData ( imageData ) )
162+ {
163+ // SVG를 PNG로 변환
164+ var pngData = ConvertSvgToPng ( imageData ) ;
165+ if ( pngData != null )
166+ {
167+ SaveBitmapData ( pngData , faviconPath ) ;
168+ }
169+ else
170+ {
171+ // 변환 실패 시 빈 문자열 설정 (기본 아이콘 사용)
172+ bookmark . FaviconPath = string . Empty ;
173+ continue ;
174+ }
175+ }
176+ else
161177 {
178+ // PNG는 그대로 저장
162179 SaveBitmapData ( imageData , faviconPath ) ;
163180 }
164-
165- bookmark . FaviconPath = faviconPath ;
166181 }
167- catch ( Exception ex )
168- {
169- Log . Exception ( $ "Failed to extract Firefox favicon: { bookmark . Url } ", ex ) ;
170- }
171- }
172182
173- // https://github.com/dotnet/efcore/issues/26580
174- SqliteConnection . ClearPool ( connection ) ;
175- connection . Close ( ) ;
176-
177- // Delete temporary file
178- try
179- {
180- File . Delete ( tempDbPath ) ;
183+ bookmark . FaviconPath = faviconPath ;
181184 }
182185 catch ( Exception ex )
183186 {
184- Log . Exception ( $ "Failed to delete temporary favicon DB : { tempDbPath } ", ex ) ;
187+ Log . Exception ( $ "Failed to extract Firefox favicon: { bookmark . Url } ", ex ) ;
185188 }
186189 }
190+
191+ // https://github.com/dotnet/efcore/issues/26580
192+ SqliteConnection . ClearPool ( connection ) ;
193+ connection . Close ( ) ;
194+
195+ // Delete temporary file
196+ try
197+ {
198+ File . Delete ( tempDbPath ) ;
199+ }
187200 catch ( Exception ex )
188201 {
189- Log . Exception ( $ "Failed to load Firefox favicon DB: { faviconDbPath } ", ex ) ;
202+ Log . Exception ( $ "Failed to delete temporary favicon DB: { tempDbPath } ", ex ) ;
190203 }
191204 }
205+ catch ( Exception ex )
206+ {
207+ Log . Exception ( $ "Failed to load Firefox favicon DB: { faviconDbPath } ", ex ) ;
208+ }
209+ }
210+
211+ private byte [ ] ConvertSvgToPng ( byte [ ] svgData )
212+ {
213+ try
214+ {
215+ using var memoryStream = new MemoryStream ( ) ;
216+ // 메모리에 SVG 데이터 로드
217+ using ( var image = new ImageMagick . MagickImage ( svgData ) )
218+ {
219+ // 적절한 크기로 리사이징 (32x32가 일반적인 파비콘 크기)
220+ image . Resize ( 32 , 32 ) ;
221+ // PNG 형식으로 변환하여 메모리 스트림에 저장
222+ image . Format = ImageMagick . MagickFormat . Png ;
223+ image . Write ( memoryStream ) ;
224+ }
225+
226+ return memoryStream . ToArray ( ) ;
227+ }
228+ catch ( Exception ex )
229+ {
230+ Log . Exception ( "SVG to PNG conversion failed" , ex ) ;
231+ return null ;
232+ }
233+ }
192234
193235 private static bool IsSvgData ( byte [ ] data )
194236 {
0 commit comments