@@ -314,77 +314,80 @@ struct Playlist: Identifiable, FetchableRecord, PersistableRecord {
314314 // Check if all tracks are from the same album
315315 let uniqueAlbums = Set ( tracks. map { $0. album } )
316316 let isSingleAlbum = uniqueAlbums. count == 1
317-
317+
318318 // If single album or single track, just use the first track's artwork
319319 if isSingleAlbum || tracks. count == 1 {
320320 return tracks. first? . artworkData
321321 }
322-
322+
323323 // Get up to 4 tracks with artwork for collage
324324 let tracksWithArt = tracks. prefix ( 4 ) . filter { $0. artworkData != nil }
325-
325+
326326 guard !tracksWithArt. isEmpty else { return nil }
327-
328- let imageSize : CGFloat = 256
329- let collageImage = NSImage ( size: NSSize ( width: imageSize, height: imageSize) )
330-
331- collageImage. lockFocus ( )
332-
333- // Clear background
334- NSColor . black. setFill ( )
335- NSRect ( x: 0 , y: 0 , width: imageSize, height: imageSize) . fill ( )
336-
327+
328+ let pixelSize = 256
329+ let colorSpace = CGColorSpaceCreateDeviceRGB ( )
330+
331+ // Create opaque bitmap context (no alpha) to avoid HEIC encoder warnings
332+ guard let context = CGContext (
333+ data: nil ,
334+ width: pixelSize,
335+ height: pixelSize,
336+ bitsPerComponent: 8 ,
337+ bytesPerRow: 0 ,
338+ space: colorSpace,
339+ bitmapInfo: CGImageAlphaInfo . noneSkipLast. rawValue
340+ ) else {
341+ Logger . warning ( " Failed to create CGContext for collage " )
342+ return nil
343+ }
344+
345+ // Fill black background
346+ context. setFillColor ( CGColor ( red: 0 , green: 0 , blue: 0 , alpha: 1 ) )
347+ context. fill ( CGRect ( x: 0 , y: 0 , width: pixelSize, height: pixelSize) )
348+
337349 let count = tracksWithArt. count
338-
339- // Special handling based on track count
350+ let size = CGFloat ( pixelSize )
351+
340352 if count == 1 {
341- // Single track - just draw it full size (this case is already handled above, but keeping for safety)
342353 if let artworkData = tracksWithArt [ 0 ] . artworkData,
343- let image = NSImage ( data: artworkData) {
344- image. draw ( in: NSRect ( x: 0 , y: 0 , width: imageSize, height: imageSize) ,
345- from: NSRect ( origin: . zero, size: image. size) ,
346- operation: . copy,
347- fraction: 1.0 )
354+ let source = CGImageSourceCreateWithData ( artworkData as CFData , nil ) ,
355+ let cgImage = CGImageSourceCreateImageAtIndex ( source, 0 , nil ) {
356+ context. draw ( cgImage, in: CGRect ( x: 0 , y: 0 , width: size, height: size) )
348357 }
349358 } else {
350359 // 2 or more tracks - always create 2x2 grid
351- let positions = [ ( 0 , 0 ) , ( 1 , 0 ) , ( 0 , 1 ) , ( 1 , 1 ) ] // (col, row) for each quadrant
352-
360+ let positions = [ ( 0 , 0 ) , ( 1 , 0 ) , ( 0 , 1 ) , ( 1 , 1 ) ]
361+
353362 for (index, ( col, row) ) in positions. enumerated ( ) {
354363 let trackIndex : Int
355-
364+
356365 if count == 2 {
357- // For 2 tracks: diagonal pattern (0, 1, 1, 0)
358366 trackIndex = ( index == 0 || index == 3 ) ? 0 : 1
359367 } else {
360- // For 3+ tracks: use available tracks, repeating if necessary
361368 trackIndex = index % count
362369 }
363-
370+
364371 guard let artworkData = tracksWithArt [ trackIndex] . artworkData,
365- let image = NSImage ( data: artworkData) else { continue }
366-
367- let destRect = NSRect (
368- x: CGFloat ( col) * imageSize / 2 ,
369- y: CGFloat ( row) * imageSize / 2 ,
370- width: imageSize / 2 ,
371- height: imageSize / 2
372+ let source = CGImageSourceCreateWithData ( artworkData as CFData , nil ) ,
373+ let cgImage = CGImageSourceCreateImageAtIndex ( source, 0 , nil ) else { continue }
374+
375+ let destRect = CGRect (
376+ x: CGFloat ( col) * size / 2 ,
377+ y: CGFloat ( row) * size / 2 ,
378+ width: size / 2 ,
379+ height: size / 2
372380 )
373-
374- image. draw ( in: destRect,
375- from: NSRect ( origin: . zero, size: image. size) ,
376- operation: . copy,
377- fraction: 1.0 )
381+
382+ context. draw ( cgImage, in: destRect)
378383 }
379384 }
380-
381- collageImage. unlockFocus ( )
382-
383- guard let cgImage = collageImage. cgImage ( forProposedRect: nil , context: nil , hints: nil ) else {
384- Logger . warning ( " Failed to create CGImage from collage " )
385+
386+ guard let collageImage = context. makeImage ( ) else {
387+ Logger . warning ( " Failed to create CGImage from collage context " )
385388 return nil
386389 }
387- return ImageUtils . encodeHEIC ( cgImage )
390+ return ImageUtils . encodeHEIC ( collageImage )
388391 }
389392}
390393
0 commit comments