diff --git a/Sources/Generator/Content/Element.swift b/Sources/Generator/Content/Element.swift index 2aa4b11..80ed26a 100644 --- a/Sources/Generator/Content/Element.swift +++ b/Sources/Generator/Content/Element.swift @@ -312,11 +312,12 @@ extension Element { var linkedElements: [LinkedElement] { let items = sortedItems - return items.enumerated().map { i, element in + let connected = items.enumerated().map { i, element in let previous = i+1 < items.count ? items[i+1] : nil let next = i > 0 ? items[i-1] : nil return (previous, element, next) } + return connected + elements.filter { !$0.state.isShownInOverview }.map { (nil, $0, nil )} } /** diff --git a/Sources/Generator/Extensions/NSImage+Extensions.swift b/Sources/Generator/Extensions/NSImage+Extensions.swift index a633e5c..a675e3f 100644 --- a/Sources/Generator/Extensions/NSImage+Extensions.swift +++ b/Sources/Generator/Extensions/NSImage+Extensions.swift @@ -7,8 +7,8 @@ extension NSImage { guard self.size.width > size.width else { return self } - return NSImage(size: size, flipped: false) { (resizedRect) -> Bool in - self.draw(in: resizedRect) + return NSImage(size: size, flipped: false) { [weak self] (resizedRect) -> Bool in + self?.draw(in: resizedRect) return true } } diff --git a/Sources/Generator/Files/ImageGenerator.swift b/Sources/Generator/Files/ImageGenerator.swift index 0a49bad..5a97aed 100644 --- a/Sources/Generator/Files/ImageGenerator.swift +++ b/Sources/Generator/Files/ImageGenerator.swift @@ -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 }