Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions SDWebImageWebPCoder/Classes/SDImageWebPCoder.m
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,9 @@ - (nullable NSData *)sd_encodedWebpDataWithImage:(nullable CGImageRef)imageRef
}

size_t bytesPerRow = CGImageGetBytesPerRow(imageRef);
size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef);
size_t bitsPerPixel = CGImageGetBitsPerPixel(imageRef);
size_t components = bitsPerPixel / bitsPerComponent;
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
CGImageAlphaInfo alphaInfo = bitmapInfo & kCGBitmapAlphaInfoMask;
CGBitmapInfo byteOrderInfo = bitmapInfo & kCGBitmapByteOrderMask;
Expand Down Expand Up @@ -763,10 +766,15 @@ - (nullable NSData *)sd_encodedWebpDataWithImage:(nullable CGImageRef)imageRef
if (!dataRef) {
return nil;
}
// Check colorSpace is RGB/RGBA
CGColorSpaceRef colorSpace = CGImageGetColorSpace(imageRef);
BOOL isRGB = CGColorSpaceGetModel(colorSpace) == kCGColorSpaceModelRGB;

uint8_t *rgba = NULL; // RGBA Buffer managed by CFData, don't call `free` on it, instead call `CFRelease` on `dataRef`
// We could not assume that input CGImage's color mode is always RGB888/RGBA8888. Convert all other cases to target color mode using vImage
if (byteOrderNormal && ((alphaInfo == kCGImageAlphaNone) || (alphaInfo == kCGImageAlphaLast))) {
BOOL isRGB888 = isRGB && byteOrderNormal && alphaInfo == kCGImageAlphaNone && components == 3;
BOOL isRGBA8888 = isRGB && byteOrderNormal && alphaInfo == kCGImageAlphaLast && components == 4;
if (isRGB888 || isRGBA8888) {
// If the input CGImage is already RGB888/RGBA8888
rgba = (uint8_t *)CFDataGetBytePtr(dataRef);
} else {
Expand All @@ -775,10 +783,11 @@ - (nullable NSData *)sd_encodedWebpDataWithImage:(nullable CGImageRef)imageRef
vImage_Error error = kvImageNoError;

vImage_CGImageFormat srcFormat = {
.bitsPerComponent = (uint32_t)CGImageGetBitsPerComponent(imageRef),
.bitsPerPixel = (uint32_t)CGImageGetBitsPerPixel(imageRef),
.colorSpace = CGImageGetColorSpace(imageRef),
.bitmapInfo = bitmapInfo
.bitsPerComponent = (uint32_t)bitsPerComponent,
.bitsPerPixel = (uint32_t)bitsPerPixel,
.colorSpace = colorSpace,
.bitmapInfo = bitmapInfo,
.renderingIntent = CGImageGetRenderingIntent(imageRef)
};
vImage_CGImageFormat destFormat = {
.bitsPerComponent = 8,
Expand All @@ -793,14 +802,15 @@ - (nullable NSData *)sd_encodedWebpDataWithImage:(nullable CGImageRef)imageRef
return nil;
}

vImage_Buffer src = {
.data = (uint8_t *)CFDataGetBytePtr(dataRef),
.width = width,
.height = height,
.rowBytes = bytesPerRow
};
vImage_Buffer dest;
vImage_Buffer src;
error = vImageBuffer_InitWithCGImage(&src, &srcFormat, nil, imageRef, kvImageNoFlags);
if (error != kvImageNoError) {
vImageConverter_Release(convertor);
CFRelease(dataRef);
return nil;
}

vImage_Buffer dest;
error = vImageBuffer_Init(&dest, height, width, destFormat.bitsPerPixel, kvImageNoFlags);
if (error != kvImageNoError) {
vImageConverter_Release(convertor);
Expand Down
Binary file added Tests/Images/TestImageGrayscale.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions Tests/SDWebImageWebPCoderTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,35 @@ - (void)testEncodingSettingsIncorrectType {
expect(config.method).to.equal(4);
}


- (void)testEncodingGrayscaleImage {
NSURL *grayscaleImageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageGrayscale" withExtension:@"jpg"];
NSData *grayscaleImageData = [NSData dataWithContentsOfURL:grayscaleImageURL];
UIImage *grayscaleImage = [[UIImage alloc] initWithData:grayscaleImageData];
expect(grayscaleImage).notTo.beNil();

NSData *webpData = [SDImageWebPCoder.sharedCoder encodedDataWithImage:grayscaleImage format:SDImageFormatWebP options:nil];
expect(webpData).notTo.beNil();

UIImage *decodedImage = [UIImage sd_imageWithData:webpData];
expect(decodedImage).notTo.beNil();

// Sample to verify that encoded WebP image's color is correct.
// The wrong case before bugfix is that each column color will repeats 3 times.
CGPoint point1 = CGPointMake(271, 764);
CGPoint point2 = CGPointMake(round(point1.x + decodedImage.size.width / 3), point1.y);
UIColor *color1 = [decodedImage sd_colorAtPoint:point1];
UIColor *color2 = [decodedImage sd_colorAtPoint:point2];
CGFloat r1, r2;
CGFloat g1, g2;
CGFloat b1, b2;
[color1 getRed:&r1 green:&g1 blue:&b1 alpha:nil];
[color2 getRed:&r2 green:&g2 blue:&b2 alpha:nil];
expect(255 * r1).notTo.equal(255 * r2);
expect(255 * g1).notTo.equal(255 * g2);
expect(255 * b1).notTo.equal(255 * b2);
}

@end

@implementation SDWebImageWebPCoderTests (Helpers)
Expand Down
4 changes: 4 additions & 0 deletions Tests/SDWebImageWebPCoderTests.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
0EF5B6264833B7BC20894578 /* Pods_SDWebImageWebPCoderTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 46F21AD7D1692EBAC4D0FF33 /* Pods_SDWebImageWebPCoderTests.framework */; };
3219F3B2228B0453003822A6 /* TestImageBlendAnimated.webp in Resources */ = {isa = PBXBuildFile; fileRef = 3219F3B1228B0453003822A6 /* TestImageBlendAnimated.webp */; };
325E268E25C82BE1000B807B /* TestImageGrayscale.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 325E268D25C82BE1000B807B /* TestImageGrayscale.jpg */; };
808C918E213FD131004B0F7C /* SDWebImageWebPCoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 808C918D213FD131004B0F7C /* SDWebImageWebPCoderTests.m */; };
808C919C213FD2B2004B0F7C /* TestImageStatic.webp in Resources */ = {isa = PBXBuildFile; fileRef = 808C919A213FD2B2004B0F7C /* TestImageStatic.webp */; };
808C919D213FD2B2004B0F7C /* TestImageAnimated.webp in Resources */ = {isa = PBXBuildFile; fileRef = 808C919B213FD2B2004B0F7C /* TestImageAnimated.webp */; };
Expand All @@ -17,6 +18,7 @@
/* Begin PBXFileReference section */
28D8AA3D3015E075692FD3E3 /* Pods-SDWebImageWebPCoderTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImageWebPCoderTests.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-SDWebImageWebPCoderTests/Pods-SDWebImageWebPCoderTests.debug.xcconfig"; sourceTree = "<group>"; };
3219F3B1228B0453003822A6 /* TestImageBlendAnimated.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageBlendAnimated.webp; sourceTree = "<group>"; };
325E268D25C82BE1000B807B /* TestImageGrayscale.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = TestImageGrayscale.jpg; sourceTree = "<group>"; };
46F21AD7D1692EBAC4D0FF33 /* Pods_SDWebImageWebPCoderTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImageWebPCoderTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
808C918B213FD130004B0F7C /* SDWebImageWebPCoderTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SDWebImageWebPCoderTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
808C918D213FD131004B0F7C /* SDWebImageWebPCoderTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageWebPCoderTests.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -78,6 +80,7 @@
808C9199213FD2B2004B0F7C /* Images */ = {
isa = PBXGroup;
children = (
325E268D25C82BE1000B807B /* TestImageGrayscale.jpg */,
808C919A213FD2B2004B0F7C /* TestImageStatic.webp */,
808C919B213FD2B2004B0F7C /* TestImageAnimated.webp */,
3219F3B1228B0453003822A6 /* TestImageBlendAnimated.webp */,
Expand Down Expand Up @@ -154,6 +157,7 @@
3219F3B2228B0453003822A6 /* TestImageBlendAnimated.webp in Resources */,
808C919D213FD2B2004B0F7C /* TestImageAnimated.webp in Resources */,
808C919C213FD2B2004B0F7C /* TestImageStatic.webp in Resources */,
325E268E25C82BE1000B807B /* TestImageGrayscale.jpg in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down