Merge pull request #3370 from dreampiggy/bugfix_pdf_draw_bitmap_dpi

Fix the PDF image without thumbnailPixelSize will result huge bitmap size, now fixed into 72 DPI matching PDFKit
This commit is contained in:
DreamPiggy 2022-07-14 15:24:11 +08:00 committed by GitHub
commit 4d4e631183
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 68 additions and 33 deletions

View File

@ -198,13 +198,6 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
exifOrientation = kCGImagePropertyOrientationUp; exifOrientation = kCGImagePropertyOrientationUp;
} }
CFStringRef uttype = CGImageSourceGetType(source);
// Check vector format
BOOL isVector = NO;
if ([NSData sd_imageFormatFromUTType:uttype] == SDImageFormatPDF) {
isVector = YES;
}
NSMutableDictionary *decodingOptions; NSMutableDictionary *decodingOptions;
if (options) { if (options) {
decodingOptions = [NSMutableDictionary dictionaryWithDictionary:options]; decodingOptions = [NSMutableDictionary dictionaryWithDictionary:options];
@ -214,22 +207,6 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
CGImageRef imageRef; CGImageRef imageRef;
BOOL createFullImage = thumbnailSize.width == 0 || thumbnailSize.height == 0 || pixelWidth == 0 || pixelHeight == 0 || (pixelWidth <= thumbnailSize.width && pixelHeight <= thumbnailSize.height); BOOL createFullImage = thumbnailSize.width == 0 || thumbnailSize.height == 0 || pixelWidth == 0 || pixelHeight == 0 || (pixelWidth <= thumbnailSize.width && pixelHeight <= thumbnailSize.height);
if (createFullImage) { if (createFullImage) {
if (isVector) {
if (thumbnailSize.width == 0 || thumbnailSize.height == 0) {
// Provide the default pixel count for vector images, simply just use the screen size
#if SD_WATCH
thumbnailSize = WKInterfaceDevice.currentDevice.screenBounds.size;
#elif SD_UIKIT
thumbnailSize = UIScreen.mainScreen.bounds.size;
#elif SD_MAC
thumbnailSize = NSScreen.mainScreen.frame.size;
#endif
}
CGFloat maxPixelSize = MAX(thumbnailSize.width, thumbnailSize.height);
NSUInteger DPIPerPixel = 2;
NSUInteger rasterizationDPI = maxPixelSize * DPIPerPixel;
decodingOptions[kSDCGImageSourceRasterizationDPI] = @(rasterizationDPI);
}
imageRef = CGImageSourceCreateImageAtIndex(source, index, (__bridge CFDictionaryRef)[decodingOptions copy]); imageRef = CGImageSourceCreateImageAtIndex(source, index, (__bridge CFDictionaryRef)[decodingOptions copy]);
} else { } else {
decodingOptions[(__bridge NSString *)kCGImageSourceCreateThumbnailWithTransform] = @(preserveAspectRatio); decodingOptions[(__bridge NSString *)kCGImageSourceCreateThumbnailWithTransform] = @(preserveAspectRatio);

View File

@ -13,6 +13,8 @@
#import "UIImage+Metadata.h" #import "UIImage+Metadata.h"
#import "SDImageIOAnimatedCoderInternal.h" #import "SDImageIOAnimatedCoderInternal.h"
// Specify DPI for vector format in CGImageSource, like PDF
static NSString * kSDCGImageSourceRasterizationDPI = @"kCGImageSourceRasterizationDPI";
// Specify File Size for lossy format encoding, like JPEG // Specify File Size for lossy format encoding, like JPEG
static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestinationRequestedFileSize"; static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestinationRequestedFileSize";
@ -52,6 +54,31 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
return coder; return coder;
} }
#pragma mark - Utils
+ (CGRect)boxRectFromPDFFData:(nonnull NSData *)data {
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
if (!provider) {
return CGRectZero;
}
CGPDFDocumentRef document = CGPDFDocumentCreateWithProvider(provider);
CGDataProviderRelease(provider);
if (!document) {
return CGRectZero;
}
// `CGPDFDocumentGetPage` page number is 1-indexed.
CGPDFPageRef page = CGPDFDocumentGetPage(document, 1);
if (!page) {
CGPDFDocumentRelease(document);
return CGRectZero;
}
CGRect boxRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
CGPDFDocumentRelease(document);
return boxRect;
}
#pragma mark - Decode #pragma mark - Decode
- (BOOL)canDecodeFromData:(nullable NSData *)data { - (BOOL)canDecodeFromData:(nullable NSData *)data {
return YES; return YES;
@ -88,13 +115,39 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
return nil; return nil;
} }
UIImage *image = [SDImageIOAnimatedCoder createFrameAtIndex:0 source:source scale:scale preserveAspectRatio:preserveAspectRatio thumbnailSize:thumbnailSize options:nil]; CFStringRef uttype = CGImageSourceGetType(source);
SDImageFormat imageFormat = [NSData sd_imageFormatFromUTType:uttype];
// Check vector format
NSDictionary *decodingOptions = nil;
if (imageFormat == SDImageFormatPDF) {
// Use 72 DPI (1:1 inch to pixel) by default, matching Apple's PDFKit behavior
NSUInteger rasterizationDPI = 72;
CGFloat maxPixelSize = MAX(thumbnailSize.width, thumbnailSize.height);
if (maxPixelSize > 0) {
// Calculate DPI based on PDF box and pixel size
CGRect boxRect = [self.class boxRectFromPDFFData:data];
CGFloat maxBoxSize = MAX(boxRect.size.width, boxRect.size.height);
if (maxBoxSize > 0) {
rasterizationDPI = rasterizationDPI * (maxPixelSize / maxBoxSize);
}
}
decodingOptions = @{
// This option will cause ImageIO return the pixel size from `CGImageSourceCopyProperties`
// If not provided, it always return 0 size
kSDCGImageSourceRasterizationDPI : @(rasterizationDPI),
};
// Already calculated DPI, avoid re-calculation based on thumbnail information
preserveAspectRatio = YES;
thumbnailSize = CGSizeZero;
}
UIImage *image = [SDImageIOAnimatedCoder createFrameAtIndex:0 source:source scale:scale preserveAspectRatio:preserveAspectRatio thumbnailSize:thumbnailSize options:decodingOptions];
CFRelease(source); CFRelease(source);
if (!image) { if (!image) {
return nil; return nil;
} }
image.sd_imageFormat = [NSData sd_imageFormatForImageData:data]; image.sd_imageFormat = imageFormat;
return image; return image;
} }

View File

@ -11,6 +11,12 @@
#import "UIColor+SDHexString.h" #import "UIColor+SDHexString.h"
#import <SDWebImageWebPCoder/SDWebImageWebPCoder.h> #import <SDWebImageWebPCoder/SDWebImageWebPCoder.h>
@interface SDImageIOCoder ()
+ (CGRect)boxRectFromPDFFData:(nonnull NSData *)data;
@end
@interface SDWebImageDecoderTests : SDTestCase @interface SDWebImageDecoderTests : SDTestCase
@end @end
@ -437,15 +443,14 @@ withLocalImageURL:(NSURL *)imageUrl
CGFloat pixelHeight = inputImage.size.height; CGFloat pixelHeight = inputImage.size.height;
expect(pixelWidth).beGreaterThan(0); expect(pixelWidth).beGreaterThan(0);
expect(pixelHeight).beGreaterThan(0); expect(pixelHeight).beGreaterThan(0);
// check vector format supports thumbnail with screen size // check vector format should use 72 DPI
if (isVector) { if (isVector) {
#if SD_UIKIT CGRect boxRect = [SDImageIOCoder boxRectFromPDFFData:inputImageData];
CGFloat maxScreenSize = MAX(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height); expect(boxRect.size.width).beGreaterThan(0);
#else expect(boxRect.size.height).beGreaterThan(0);
CGFloat maxScreenSize = MAX(NSScreen.mainScreen.frame.size.width, NSScreen.mainScreen.frame.size.height); // Since 72 DPI is 1:1 from inch size to pixel size
#endif expect(boxRect.size.width).equal(pixelWidth);
expect(pixelWidth).equal(maxScreenSize); expect(boxRect.size.height).equal(pixelHeight);
expect(pixelHeight).equal(maxScreenSize);
} }
// check thumbnail with scratch // check thumbnail with scratch