Calculate the DPI based on PDF mediaBox, support thumbnailPixelSize

Move the vector code from ImageIOAnimatedCoder to ImageIOCoder, since it's not animatable :)
This commit is contained in:
DreamPiggy 2022-07-13 18:18:21 +08:00
parent f91d35ef8d
commit f1fe4ca8b8
3 changed files with 63 additions and 22 deletions

View File

@ -197,13 +197,6 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
if (!exifOrientation) {
exifOrientation = kCGImagePropertyOrientationUp;
}
CFStringRef uttype = CGImageSourceGetType(source);
// Check vector format
BOOL isVector = NO;
if ([NSData sd_imageFormatFromUTType:uttype] == SDImageFormatPDF) {
isVector = YES;
}
NSMutableDictionary *decodingOptions;
if (options) {
@ -214,11 +207,6 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
CGImageRef imageRef;
BOOL createFullImage = thumbnailSize.width == 0 || thumbnailSize.height == 0 || pixelWidth == 0 || pixelHeight == 0 || (pixelWidth <= thumbnailSize.width && pixelHeight <= thumbnailSize.height);
if (createFullImage) {
if (isVector) {
// Use 72 DPI by default, matching Apple's PDFKit behavior
NSUInteger rasterizationDPI = 72;
decodingOptions[kSDCGImageSourceRasterizationDPI] = @(rasterizationDPI);
}
imageRef = CGImageSourceCreateImageAtIndex(source, index, (__bridge CFDictionaryRef)[decodingOptions copy]);
} else {
decodingOptions[(__bridge NSString *)kCGImageSourceCreateThumbnailWithTransform] = @(preserveAspectRatio);

View File

@ -13,6 +13,8 @@
#import "UIImage+Metadata.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
static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestinationRequestedFileSize";
@ -52,6 +54,31 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
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
- (BOOL)canDecodeFromData:(nullable NSData *)data {
return YES;
@ -88,13 +115,34 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
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 = @{
kSDCGImageSourceRasterizationDPI : @(rasterizationDPI),
};
}
UIImage *image = [SDImageIOAnimatedCoder createFrameAtIndex:0 source:source scale:scale preserveAspectRatio:preserveAspectRatio thumbnailSize:thumbnailSize options:decodingOptions];
CFRelease(source);
if (!image) {
return nil;
}
image.sd_imageFormat = [NSData sd_imageFormatForImageData:data];
image.sd_imageFormat = imageFormat;
return image;
}

View File

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