Fix memory leaks, sizes for image generation

This commit is contained in:
Christoph Hagen
2022-09-26 17:00:25 +02:00
parent 152a76935b
commit b39066f47f
3 changed files with 42 additions and 30 deletions

View File

@ -204,14 +204,13 @@ final class ImageGenerator {
missingImages[source] = images.first?.path
return
}
if imageHasChanged {
// Update all images
images.forEach { create(job: $0, from: image, source: source) }
} else {
// Update only missing images
images
.filter(isMissing)
.forEach { create(job: $0, from: image, source: source) }
let jobs = imageHasChanged ? images : images.filter(isMissing)
// Update all images
jobs.forEach { job in
// Prevent memory overflow due to repeated NSImage operations
autoreleasepool {
create(job: job, from: image, source: source)
}
}
}
@ -224,31 +223,43 @@ final class ImageGenerator {
fatalError()
}
let desiredWidth = CGFloat(image.size.width)
let destinationSize = image.size.scaledDown(to: desiredWidth)
let scaledImage = image.scaledDown(to: destinationSize)
let scaledSize = scaledImage.size
if abs(scaledSize.width - desiredWidth) > 2 {
addWarning("Invalid width (\(scaledSize.width) instead of \(desiredWidth))", job: job)
}
if scaledSize.width > desiredWidth {
addWarning("Invalid width (\(scaledSize.width) instead of \(desiredWidth))", job: job)
}
let destinationExtension = destinationUrl.pathExtension.lowercased()
guard let type = ImageType(fileExtension: destinationExtension)?.fileType else {
addWarning("Invalid image extension \(destinationExtension)", job: job)
return
}
guard let tiff = scaledImage.tiffRepresentation, let tiffData = NSBitmapImageRep(data: tiff) else {
addWarning("Failed to get data", job: job)
return
}
guard let data = tiffData.representation(using: type, properties: [.compressionFactor: NSNumber(0.7)]) else {
let desiredWidth = CGFloat(job.width)
let sourceRep = image.representations[0]
let destinationSize = NSSize(width: sourceRep.pixelsWide, height: sourceRep.pixelsHigh)
.scaledDown(to: desiredWidth)
//image.size.scaledDown(to: desiredWidth)
print("\(job.destination):")
print(" Source: \(image.size.width) x \(image.size.height)")
print(" Wanted: \(destinationSize.width) x \(destinationSize.height) (\(job.width))")
// create NSBitmapRep manually, if using cgImage, the resulting size is wrong
let rep = NSBitmapImageRep(bitmapDataPlanes: nil,
pixelsWide: Int(destinationSize.width),
pixelsHigh: Int(destinationSize.height),
bitsPerSample: 8,
samplesPerPixel: 4,
hasAlpha: true,
isPlanar: false,
colorSpaceName: NSColorSpaceName.deviceRGB,
bytesPerRow: Int(destinationSize.width) * 4,
bitsPerPixel: 32)!
let ctx = NSGraphicsContext(bitmapImageRep: rep)
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.current = ctx
image.draw(in: NSMakeRect(0, 0, destinationSize.width, destinationSize.height))
ctx?.flushGraphics()
NSGraphicsContext.restoreGraphicsState()
// Get NSData, and save it
guard let data = rep.representation(using: type, properties: [.compressionFactor: NSNumber(0.7)]) else {
addWarning("Failed to get data", job: job)
return
}