Skip to content

Commit

Permalink
Revert "We won't create CGColorSpaceRefs ourselves today."
Browse files Browse the repository at this point in the history
This reverts commit 71ecfa1.
  • Loading branch information
ledyba-z committed Mar 13, 2020
1 parent 08d5172 commit 9da58e8
Showing 1 changed file with 272 additions and 12 deletions.
284 changes: 272 additions & 12 deletions SDWebImageAVIFCoder/Classes/SDImageAVIFCoder.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,196 @@ static void FreeImageData(void *info, const void *data, size_t size) {
free((void *)data);
}

static void CalcWhitePoint(uint16_t const colorPrimaries, vImageWhitePoint* const white) {
float primaries[8];
avifNclxColourPrimariesGetValues(colorPrimaries, primaries);
white->white_x = primaries[6];
white->white_y = primaries[7];
}

static void CalcRGBPrimaries(uint16_t const colorPrimaries, vImageRGBPrimaries* const prim) {
float primaries[8];
avifNclxColourPrimariesGetValues(colorPrimaries, primaries);
prim->red_x = primaries[0];
prim->red_y = primaries[1];
prim->green_x = primaries[2];
prim->green_y = primaries[3];
prim->blue_x = primaries[4];
prim->blue_y = primaries[5];
prim->white_x = primaries[6];
prim->white_y = primaries[7];
}

static void CalcTransferFunction(uint16_t const transferCharacteristics, vImageTransferFunction* const tf) {
// See: https://www.itu.int/rec/T-REC-H.273/en
static const float alpha = 1.099296826809442f;
static const float beta = 0.018053968510807f;
/*
// R' = c0 * pow( c1 * R + c2, gamma ) + c3, (R >= cutoff)
// R' = c4 * R + c5 (R < cutoff)
*/

switch(transferCharacteristics) {
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_GAMMA28: // 5
tf->cutoff = -INFINITY;
tf->c0 = 1.0f;
tf->c1 = 1.0f;
tf->c2 = 0.0f;
tf->c3 = 0.0f;
tf->c4 = 0.0f;
tf->c5 = 0.0f;
tf->gamma = 1.0f/2.8f;
break;
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT709: // 1
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT601: // 6
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT2020_10BIT: // 14
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT2020_12BIT: // 15
tf->cutoff = beta;
//
tf->c0 = alpha;
tf->c1 = 1.0f;
tf->c2 = 0.0f;
tf->gamma = 0.45f;
tf->c3 = -(alpha - 1);
//
tf->c4 = 4.5f;
tf->c5 = 0.0f;
break;
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_ST240: // 7
tf->cutoff = beta;
//
tf->c0 = alpha;
tf->c1 = 1.0f;
tf->c2 = 0.0f;
tf->gamma = 0.45f;
tf->c3 = -(alpha - 1);
//
tf->c4 = 4.0f;
tf->c5 = 0.0f;
break;
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_LINEAR: // 8
tf->cutoff = INFINITY;
//
tf->c0 = 1.0f;
tf->c1 = 1.0f;
tf->c2 = 0.0f;
tf->gamma = 1.0f;
tf->c3 = 0.0f;
//
tf->c4 = 4.0f;
tf->c5 = 0.0f;
break;
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_IEC61966: // 11
tf->cutoff = beta;
//
tf->c0 = alpha;
tf->c1 = 1.0f;
tf->c2 = 0.0f;
tf->gamma = 0.45f;
tf->c3 = -(alpha - 1);
//
tf->c4 = 4.5f;
tf->c5 = 0.0f;
break;
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT1361_EXTENDED: // 12
tf->cutoff = beta;
//
tf->c0 = alpha;
tf->c1 = 1.0f;
tf->c2 = 0.0f;
tf->gamma = 0.45f;
tf->c3 = -(alpha - 1);
//
tf->c4 = 4.5f;
tf->c5 = 0.0f;
break;
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_SRGB: // 13
tf->cutoff = beta;
//
tf->c0 = alpha;
tf->c1 = 1.0f;
tf->c2 = 0.0f;
tf->gamma = 1.0f/2.4f;
tf->c3 = -(alpha - 1);
//
tf->c4 = 12.92f;
tf->c5 = 0.0f;
break;
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_ST428: // 17
tf->cutoff = -INFINITY;
//
tf->c0 = 1.0f;
tf->c1 = 48.0f / 52.37f;
tf->c2 = 0.0f;
tf->gamma = 1.0f/2.6f;
tf->c3 = 0.0f;
//
tf->c4 = 1.0f;
tf->c5 = 0.0f;
break;
// Can't be represented by vImageTransferFunction. Use gamma 2.2 as a fallback.
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_ST2084: // 16
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT2100_HLG: // 18
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_LOG_100_1: // 9
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_LOG_100_SQRT: // 10
//
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_UNKNOWN: // 0
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_UNSPECIFIED: // 2
case AVIF_NCLX_TRANSFER_CHARACTERISTICS_GAMMA22: // 4
default:
tf->cutoff = -INFINITY;
tf->c0 = 1.0f;
tf->c1 = 1.0f;
tf->c2 = 0.0f;
tf->c3 = 0.0f;
tf->c4 = 0.0f;
tf->c5 = 0.0f;
tf->gamma = 1.0f/2.2f;
break;
}
}
static CGColorSpaceRef CreateColorSpaceMono(uint16_t const colorPrimaries, uint16_t const transferCharacteristics) {
if (@available(macOS 10.10, iOS 8.0, tvOS 8.0, *)) {
vImage_Error err;
vImageWhitePoint white;
vImageTransferFunction transfer;
CalcWhitePoint(colorPrimaries, &white);
CalcTransferFunction(transferCharacteristics, &transfer);
CGColorSpaceRef colorSpace = vImageCreateMonochromeColorSpaceWithWhitePointAndTransferFunction(&white, &transfer, kCGRenderingIntentDefault, kvImagePrintDiagnosticsToConsole, &err);
if(err != kvImageNoError) {
NSLog(@"[BUG] Failed to create monochrome color space: %ld", err);
if(colorSpace != NULL) {
CGColorSpaceRelease(colorSpace);
}
return NULL;
}
return colorSpace;
}else{
return NULL;
}
}

static CGColorSpaceRef CreateColorSpaceRGB(uint16_t const colorPrimaries, uint16_t const transferCharacteristics) {
if (@available(macOS 10.10, iOS 8.0, tvOS 8.0, *)) {
vImage_Error err;
vImageRGBPrimaries primaries;
vImageTransferFunction transfer;
CalcRGBPrimaries(colorPrimaries, &primaries);
CalcTransferFunction(transferCharacteristics, &transfer);
CGColorSpaceRef colorSpace = vImageCreateRGBColorSpaceWithPrimariesAndTransferFunction(&primaries, &transfer, kCGRenderingIntentDefault, kvImagePrintDiagnosticsToConsole, &err);
if(err != kvImageNoError) {
NSLog(@"[BUG] Failed to create monochrome color space: %ld", err);
if(colorSpace != NULL) {
CGColorSpaceRelease(colorSpace);
}
return NULL;
}
return colorSpace;
}else{
return NULL;
}
}

static void CalcColorSpaceMono(avifImage * avif, CGColorSpaceRef* ref, BOOL* shouldRelease) {
static CGColorSpaceRef defaultColorSpace;
{
Expand Down Expand Up @@ -46,12 +236,81 @@ static void CalcColorSpaceMono(avifImage * avif, CGColorSpaceRef* ref, BOOL* sho
*shouldRelease = FALSE;
return;
}
// TODO: (ledyba-z):
// We can support other color spaces using
// vImageCreateMonochromeColorSpaceWithWhitePointAndTransferFunction
// https://github.com/link-u/SDWebImageAVIFCoder/tree/feature/create-custom-colorspaces
*ref = defaultColorSpace;
*shouldRelease = FALSE;
uint16_t const colorPrimaries = avif->nclx.colourPrimaries;
uint16_t const transferCharacteristics = avif->nclx.transferCharacteristics;
if((colorPrimaries == AVIF_NCLX_COLOUR_PRIMARIES_UNKNOWN ||
colorPrimaries == AVIF_NCLX_COLOUR_PRIMARIES_UNSPECIFIED) &&
(transferCharacteristics == AVIF_NCLX_TRANSFER_CHARACTERISTICS_UNKNOWN ||
transferCharacteristics == AVIF_NCLX_TRANSFER_CHARACTERISTICS_UNSPECIFIED)) {
*ref = defaultColorSpace;
*shouldRelease = FALSE;
return;
}
if(colorPrimaries == AVIF_NCLX_COLOUR_PRIMARIES_SRGB &&
transferCharacteristics == AVIF_NCLX_TRANSFER_CHARACTERISTICS_SRGB) {
static CGColorSpaceRef sRGB = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sRGB = CreateColorSpaceMono(colorPrimaries, transferCharacteristics);
if(sRGB == NULL) {
sRGB = defaultColorSpace;
}
});
*ref = sRGB;
*shouldRelease = FALSE;
return;
}
if(colorPrimaries == AVIF_NCLX_COLOUR_PRIMARIES_BT709 &&
transferCharacteristics == AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT709) {
static CGColorSpaceRef bt709 = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
bt709 = CreateColorSpaceMono(colorPrimaries, transferCharacteristics);
if(bt709 == NULL) {
bt709 = defaultColorSpace;
}
});
*ref = bt709;
*shouldRelease = FALSE;
return;
}
if(colorPrimaries == AVIF_NCLX_COLOUR_PRIMARIES_BT2020 &&
(transferCharacteristics == AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT2020_10BIT ||
transferCharacteristics == AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT2020_12BIT)) {
static CGColorSpaceRef bt2020 = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
bt2020 = CreateColorSpaceMono(colorPrimaries, transferCharacteristics);
if(bt2020 == NULL) {
bt2020 = defaultColorSpace;
}
});
*ref = bt2020;
*shouldRelease = FALSE;
return;
}
if(colorPrimaries == AVIF_NCLX_COLOUR_PRIMARIES_P3 &&
transferCharacteristics == AVIF_NCLX_TRANSFER_CHARACTERISTICS_SRGB) {
static CGColorSpaceRef p3 = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
p3 = CreateColorSpaceMono(colorPrimaries, transferCharacteristics);
if(p3 == NULL) {
p3 = defaultColorSpace;
}
});
*ref = p3;
*shouldRelease = FALSE;
return;
}

*ref = CreateColorSpaceMono(colorPrimaries, transferCharacteristics);
if(*ref != NULL) {
*shouldRelease = TRUE;
} else {
*ref = defaultColorSpace;
*shouldRelease = FALSE;
}
}

static void CalcColorSpaceRGB(avifImage * avif, CGColorSpaceRef* ref, BOOL* shouldRelease) {
Expand Down Expand Up @@ -261,12 +520,13 @@ static void CalcColorSpaceRGB(avifImage * avif, CGColorSpaceRef* ref, BOOL* shou
return;
}

// TODO: (ledyba-z):
// We can support other color spaces using
// vImageCreateRGBColorSpaceWithPrimariesAndTransferFunction
// https://github.com/link-u/SDWebImageAVIFCoder/tree/feature/create-custom-colorspaces
*ref = defaultColorSpace;
*shouldRelease = FALSE;
*ref = CreateColorSpaceRGB(colorPrimaries, transferCharacteristics);
if(*ref != NULL) {
*shouldRelease = TRUE;
} else {
*ref = defaultColorSpace;
*shouldRelease = FALSE;
}
}

static CGImageRef CreateImageFromBuffer(avifImage * avif, vImage_Buffer* result) {
Expand Down

0 comments on commit 9da58e8

Please sign in to comment.