Skip to content

Commit ab2fde9

Browse files
authored
Merge pull request #14 from link-u/fix/hdr-alpha
Scale alpha planes [0, (1 << bit-depth) - 1] to [0, 65536]
2 parents 62c8e95 + 4713673 commit ab2fde9

File tree

2 files changed

+91
-21
lines changed

2 files changed

+91
-21
lines changed

Example/Tests/Tests.m

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,9 @@ -(void)assertColor8: (NSString*)filename img:(CGImageRef)img expectedColor:(UInt
172172
for(size_t c = 0; c < 3; ++c) {
173173
int32_t result = pix[c];
174174
int32_t expected = expectedColor[c];
175-
XCTAssertTrue(ok = (abs(result - expected) <= threshold8), "(x: %ld, y: %ld, c:%ld): result=%d vs expected=%d (%@)", x, y, c, result, expected, filename);
175+
XCTAssertTrue(ok = (abs(result - expected) <= threshold8),
176+
"(x: %ld, y: %ld, c:%ld): result=%d vs expected=%d (%@)",
177+
x, y, c, result, expected, filename);
176178
}
177179
if(!ok) {
178180
goto end;
@@ -202,9 +204,13 @@ -(void)assertColorAlpha8: (NSString*)filename img:(CGImageRef)img expectedColor:
202204
for(size_t c = 1; c < 4; ++c) {
203205
int32_t result = pix[c];
204206
int32_t expected = expectedColor[c-1];
205-
XCTAssertTrue(ok &= (abs(result - expected) <= threshold8), "(x: %ld, y: %ld, c:%ld): result=%d vs expected=%d (%@)", x, y, c, result, expected, filename);
207+
XCTAssertTrue(ok &= (abs(result - expected) <= threshold8),
208+
"(x: %ld, y: %ld, c:%ld): result=%d vs expected=%d (%@)",
209+
x, y, c, result, expected, filename);
206210
}
207-
XCTAssertTrue(ok &= (pix[0] == (x < 128 ? 0xff : 0x00)), "(x: %ld, y: %ld, c: alpha): result=%d vs expected=%d (%@)", x, y, pix[0], x < 128 ? 0xff : 0x00, filename);
211+
XCTAssertTrue(ok &= (pix[0] == (x < 128 ? 0xff : 0x00)),
212+
"(x: %ld, y: %ld, c: alpha): result=%d vs expected=%d (%@)",
213+
x, y, pix[0], x < 128 ? 0xff : 0x00, filename);
208214
if(!ok) {
209215
goto end;
210216
}
@@ -233,7 +239,9 @@ -(void)assertColor16: (NSString*)filename img:(CGImageRef)img expectedColor:(UIn
233239
for(size_t c = 0; c < 3; ++c) {
234240
int32_t result = pix[c];
235241
int32_t expected = expectedColor[c];
236-
XCTAssertTrue(ok &= (abs(result - expected) <= threshold16), "(x: %ld, y: %ld, c:%ld): result=%d vs expected=%d (%@)", x, y, c, result, expected, filename);
242+
XCTAssertTrue(ok &= (abs(result - expected) <= threshold16),
243+
"(x: %ld, y: %ld, c:%ld): result=%d vs expected=%d (%@)",
244+
x, y, c, result, expected, filename);
237245
}
238246
if(!ok) {
239247
goto end;
@@ -257,15 +265,19 @@ -(void)assertColorAlpha16: (NSString*)filename img:(CGImageRef)img expectedColor
257265
XCTAssertEqual(numComponents, 4);
258266
XCTAssertEqual(bytesPerPixel, 8);
259267
for(size_t y = 0; y < height; ++y) {
260-
for(size_t x = 0; x < width; ++x) {
268+
for(size_t x = 64; x < width; x+=128) {
261269
UInt16* pix = (UInt16*)(buf + (stride * y) + (bytesPerPixel * x));
262270
bool ok = true;
263271
for(size_t c = 1; c < 4; ++c) {
264272
int32_t result = pix[c];
265273
int32_t expected = expectedColor[c-1];
266-
XCTAssertTrue(ok &= (abs(result - expected) <= threshold16), "(x: %ld, y: %ld, c:%ld): result=%d vs expected=%d (%@)", x, y, c, result, expected, filename);
274+
XCTAssertTrue(ok &= (abs(result - expected) <= threshold16),
275+
"(x: %ld, y: %ld, c:%ld): result=%d vs expected=%d (%@)",
276+
x, y, c, result, expected, filename);
267277
}
268-
XCTAssertTrue(ok &= (pix[0] == (x < 128 ? 0xffff : 0x0000)), "(x: %ld, y: %ld, c: alpha): result=%d vs expected=%d (%@)", x, y, pix[0], x < 128 ? 0xffff : 0x00, filename);
278+
XCTAssertTrue(ok &= (pix[0] == (x < 128 ? 0xffff : 0x0000)),
279+
"(x: %ld, y: %ld, c: alpha): result=%d vs expected=%d (%@)",
280+
x, y, pix[0], x < 128 ? 0xffff : 0x00, filename);
269281
if(!ok) {
270282
goto end;
271283
}
@@ -292,7 +304,9 @@ -(void)assertMono8: (NSString*)filename img:(CGImageRef)img
292304
for(size_t x = 0; x < width; ++x) {
293305
bool ok = true;
294306
UInt8* pix = (buf + (stride * y) + (bytesPerPixel * x));
295-
XCTAssertTrue(ok &= (abs(pix0 - *pix) <= threshold8), "(x: %ld, y: %ld): result=%d vs expected=%d (%@)", x, y, *pix, pix0, filename);
307+
XCTAssertTrue(ok &= (abs(pix0 - *pix) <= threshold8),
308+
"(x: %ld, y: %ld): result=%d vs expected=%d (%@)",
309+
x, y, *pix, pix0, filename);
296310
if(!ok) {
297311
goto end;
298312
}
@@ -319,8 +333,12 @@ -(void)assertMonoAlpha8: (NSString*)filename img:(CGImageRef)img
319333
for(size_t x = 64; x < width; x+=128) {
320334
bool ok = true;
321335
UInt8* pix = (buf + (stride * y) + (bytesPerPixel * x));
322-
XCTAssertTrue(ok &= (abs(pix0 - pix[1]) <= threshold8), "(x: %ld, y: %ld, c: mono): result=%d vs expected=%d (%@)", x, y, pix[1], pix0, filename);
323-
XCTAssertTrue(ok &= (pix[0] == (x < 128 ? 0xff : 0x00)), "(x: %ld, y: %ld, c: alpha): result=%d vs expected=%d (%@)", x, y, pix[0], x < 128 ? 0xff : 0x00, filename);
336+
XCTAssertTrue(ok &= (abs(pix0 - pix[1]) <= threshold8),
337+
"(x: %ld, y: %ld, c: mono): result=%d vs expected=%d (%@)",
338+
x, y, pix[1], pix0, filename);
339+
XCTAssertTrue(ok &= (pix[0] == (x < 128 ? 0xff : 0x00)),
340+
"(x: %ld, y: %ld, c: alpha): result=%d vs expected=%d (%@)",
341+
x, y, pix[0], x < 128 ? 0xff : 0x00, filename);
324342
if(!ok) {
325343
goto end;
326344
}
@@ -348,7 +366,9 @@ -(void)assertMono16: (NSString*)filename img:(CGImageRef)img
348366
for(size_t x = 0; x < width; ++x) {
349367
UInt16* pix = (UInt16*)(buf + (stride * y) + (bytesPerPixel * x));
350368
bool ok = true;
351-
XCTAssertTrue(ok &= (abs(pix0 - *pix) <= threshold16), "(x: %ld, y: %ld): result=%d vs expected=%d (%@)", x, y, *pix, pix0, filename);
369+
XCTAssertTrue(ok &= (abs(pix0 - *pix) <= threshold16),
370+
"(x: %ld, y: %ld): result=%d vs expected=%d (%@)",
371+
x, y, *pix, pix0, filename);
352372
if(!ok) {
353373
goto end;
354374
}
@@ -372,11 +392,15 @@ -(void)assertMonoAlpha16: (NSString*)filename img:(CGImageRef)img
372392
XCTAssertEqual(bytesPerPixel, 4);
373393
UInt16 const pix0 = ((UInt16*)buf)[1];
374394
for(size_t y = 0; y < height; ++y) {
375-
for(size_t x = 0; x < width; ++x) {
395+
for(size_t x = 64; x < width; x+=128) {
376396
UInt16* pix = (UInt16*)(buf + (stride * y) + (bytesPerPixel * x));
377397
bool ok = true;
378-
XCTAssertTrue(ok &= (abs(pix0 - pix[1]) <= threshold16), "(x: %ld, y: %ld): result=%d vs expected=%d (%@)", x, y, pix[1], pix0, filename);
379-
XCTAssertTrue(ok &= (pix[0] == (x < 128 ? 0xffff : 0x0000)), "(x: %ld, y: %ld, c: alpha): result=%d vs expected=%d (%@)", x, y, pix[0], x < 128 ? 0xffff : 0x0000, filename);
398+
XCTAssertTrue(ok &= (abs(pix0 - pix[1]) <= threshold16),
399+
"(x: %ld, y: %ld): result=%d vs expected=%d (%@)",
400+
x, y, pix[1], pix0, filename);
401+
XCTAssertTrue(ok &= (pix[0] == (x < 128 ? 0xffff : 0x0000)),
402+
"(x: %ld, y: %ld, c: alpha): result=%d vs expected=%d (%@)",
403+
x, y, pix[0], x < 128 ? 0xffff : 0x0000, filename);
380404
if(!ok) {
381405
goto end;
382406
}
@@ -420,9 +444,7 @@ - (void)assertImages: (NSMutableArray*) list colorName:(NSString*)colorName expe
420444
}
421445
}else{
422446
if([alpha isEqualToString:@"with-alpha"]) {
423-
// FIXME(ledyba-z): This issue blocks testing alpha plane:
424-
// https://github.com/AOMediaCodec/libavif/issues/86
425-
//[self assertMonoAlpha16: convertedFilename img:img.CGImage];
447+
[self assertMonoAlpha16: convertedFilename img:img.CGImage];
426448
}else{
427449
[self assertMono16: convertedFilename img:img.CGImage];
428450
}
@@ -436,9 +458,7 @@ - (void)assertImages: (NSMutableArray*) list colorName:(NSString*)colorName expe
436458
}
437459
} else {
438460
if([alpha isEqualToString:@"with-alpha"]) {
439-
// FIXME(ledyba-z): This issue blocks testing alpha plane:
440-
// https://github.com/AOMediaCodec/libavif/issues/86
441-
//[self assertColorAlpha16: convertedFilename img:img.CGImage expectedColor:expectedColor16];
461+
[self assertColorAlpha16: convertedFilename img:img.CGImage expectedColor:expectedColor16];
442462
} else {
443463
[self assertColor16: convertedFilename img:img.CGImage expectedColor:expectedColor16];
444464
}

SDWebImageAVIFCoder/Classes/SDImageAVIFCoder.m

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,10 @@ static CGImageRef CreateImage8(avifImage * avif) {
226226
origCr.rowBytes = 0;
227227
memset(origCr.data, pixelRange.CbCr_bias, origCr.width);
228228
}
229-
229+
230+
//TODO: (ledyba-z) we have to scale alpha when libavif v0.6.0 comes.
231+
// https://github.com/AOMediaCodec/libavif/issues/91
232+
230233
uint8_t const permuteMap[4] = {0, 1, 2, 3};
231234
switch(avif->yuvFormat) {
232235
case AVIF_PIXEL_FORMAT_NONE:
@@ -521,6 +524,7 @@ static CGImageRef CreateImage16U(avifImage * avif) {
521524
uint16_t* resultBufferData = NULL;
522525
uint16_t* argbBufferData = NULL;
523526
uint16_t* ayuvBufferData = NULL;
527+
uint16_t* scaledAlphaBufferData = NULL;
524528
uint16_t* dummyCbData = NULL;
525529
uint16_t* dummyCrData = NULL;
526530
uint16_t* dummyAlphaData = NULL;
@@ -637,10 +641,53 @@ static CGImageRef CreateImage16U(avifImage * avif) {
637641

638642
vImage_Buffer origAlpha = {0};
639643
if(hasAlpha) {
644+
float* floatAlphaBufferData = NULL;
645+
floatAlphaBufferData = calloc(avif->width * avif->height, sizeof(float));
646+
scaledAlphaBufferData = calloc(avif->width * avif->height, sizeof(uint16_t));
647+
if(floatAlphaBufferData == NULL || scaledAlphaBufferData == NULL) {
648+
err = kvImageMemoryAllocationError;
649+
goto end_prepare_alpha;
650+
}
640651
origAlpha.data = avif->alphaPlane;
641652
origAlpha.width = avif->width;
642653
origAlpha.height = avif->height;
643654
origAlpha.rowBytes = avif->alphaRowBytes;
655+
656+
vImage_Buffer floatAlphaBuffer = {
657+
.data = floatAlphaBufferData,
658+
.width = avif->width,
659+
.height = avif->height,
660+
.rowBytes = avif->width * sizeof(float),
661+
};
662+
vImage_Buffer scaledAlphaBuffer = {
663+
.data = scaledAlphaBufferData,
664+
.width = avif->width,
665+
.height = avif->height,
666+
.rowBytes = avif->width * sizeof(uint16_t),
667+
};
668+
err = vImageConvert_16UToF(&origAlpha, &floatAlphaBuffer, 0.0f, 1.0f, kvImageNoFlags);
669+
if(err != kvImageNoError) {
670+
NSLog(@"Failed to convert alpha planes from uint16 to float: %ld", err);
671+
goto end_prepare_alpha;
672+
}
673+
float scale = 1.0f;
674+
if(avif->depth == 10) {
675+
scale = (float)((1 << 10) - 1) / 65535.0f;
676+
} else if(avif->depth == 12) {
677+
scale = (float)((1 << 12) - 1) / 65535.0f;
678+
}
679+
err = vImageConvert_FTo16U(&floatAlphaBuffer, &scaledAlphaBuffer, 0.0f, scale, kvImageNoFlags);
680+
if(err != kvImageNoError) {
681+
NSLog(@"Failed to convert alpha planes from uint16 to float: %ld", err);
682+
goto end_prepare_alpha;
683+
}
684+
origAlpha.data = scaledAlphaBufferData;
685+
origAlpha.rowBytes = avif->width * sizeof(uint16_t);
686+
end_prepare_alpha:
687+
free(floatAlphaBufferData);
688+
if(err != kvImageNoError) {
689+
goto end_all;
690+
}
644691
} else {
645692
// allocate dummy data to convert monochrome images.
646693
origAlpha.rowBytes = avif->width * sizeof(uint16_t);
@@ -750,6 +797,8 @@ static CGImageRef CreateImage16U(avifImage * avif) {
750797
dummyCrData = NULL;
751798
free(dummyAlphaData);
752799
dummyAlphaData = NULL;
800+
free(scaledAlphaBufferData);
801+
scaledAlphaBufferData = NULL;
753802

754803
err = vImageConvert_YpCbCrToARGB_GenerateConversion(&matrix,
755804
&pixelRange,
@@ -935,6 +984,7 @@ static CGImageRef CreateImage16U(avifImage * avif) {
935984
free(resultBufferData);
936985
free(argbBufferData);
937986
free(ayuvBufferData);
987+
free(scaledAlphaBufferData);
938988
free(dummyCbData);
939989
free(dummyCrData);
940990
free(dummyAlphaData);

0 commit comments

Comments
 (0)