@@ -1210,7 +1210,8 @@ static avifResult avifEncoderCreateBitDepthExtensionItems(avifEncoder * encoder,
12101210 uint16_t colorItemID )
12111211{
12121212 AVIF_ASSERT_OR_RETURN (encoder -> sampleTransformRecipe == AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_EXTENSION_8B_8B ||
1213- encoder -> sampleTransformRecipe == AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_EXTENSION_12B_4B );
1213+ encoder -> sampleTransformRecipe == AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_EXTENSION_12B_4B ||
1214+ encoder -> sampleTransformRecipe == AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_EXTENSION_12B_8B_OVERLAP_4B );
12141215
12151216 // There are multiple possible ISOBMFF box hierarchies for translucent images,
12161217 // using 'sato' (Sample Transform) derived image items:
@@ -1300,7 +1301,52 @@ static avifResult avifImageCreateAllocate(avifImage ** sampleTransformedImage, c
13001301 return avifImageAllocatePlanes (* sampleTransformedImage , planes );
13011302}
13021303
1303- static avifResult avifEncoderCreateSatoImage (const avifEncoder * encoder ,
1304+ // Finds the encoded base image and decodes it. Callers of this function must free
1305+ // *codec and *decodedBaseImage if not null, whether the function succeeds or not.
1306+ static avifResult avifEncoderDecodeSatoBaseImage (avifEncoder * encoder ,
1307+ const avifImage * original ,
1308+ uint32_t numBits ,
1309+ avifPlanesFlag planes ,
1310+ avifCodec * * codec ,
1311+ avifImage * * decodedBaseImage )
1312+ {
1313+ avifDecodeSample sample ;
1314+ memset (& sample , 0 , sizeof (sample ));
1315+ sample .spatialID = AVIF_SPATIAL_ID_UNSET ;
1316+
1317+ // Find the encoded bytes of the base image item.
1318+ for (uint32_t itemIndex = 0 ; itemIndex < encoder -> data -> items .count ; ++ itemIndex ) {
1319+ avifEncoderItem * item = & encoder -> data -> items .item [itemIndex ];
1320+ if ((item -> itemCategory != AVIF_ITEM_COLOR || planes != AVIF_PLANES_YUV ) &&
1321+ (item -> itemCategory != AVIF_ITEM_ALPHA || planes != AVIF_PLANES_A )) {
1322+ continue ;
1323+ }
1324+
1325+ AVIF_ASSERT_OR_RETURN (item -> encodeOutput != NULL ); // TODO: Support grids?
1326+ AVIF_ASSERT_OR_RETURN (item -> encodeOutput -> samples .count == 1 );
1327+ AVIF_ASSERT_OR_RETURN (item -> encodeOutput -> samples .sample [0 ].data .size != 0 );
1328+ AVIF_ASSERT_OR_RETURN (sample .data .size == 0 ); // There should be only one base item.
1329+ sample .data .data = item -> encodeOutput -> samples .sample [0 ].data .data ;
1330+ sample .data .size = item -> encodeOutput -> samples .sample [0 ].data .size ;
1331+ }
1332+ AVIF_ASSERT_OR_RETURN (sample .data .size != 0 ); // There should be at least one base item.
1333+
1334+ // avifCodecGetNextImageFunc() uses only a few fields of its decoder argument.
1335+ avifDecoder decoder ;
1336+ memset (& decoder , 0 , sizeof (decoder ));
1337+ decoder .maxThreads = encoder -> maxThreads ;
1338+ decoder .imageSizeLimit = AVIF_DEFAULT_IMAGE_SIZE_LIMIT ;
1339+
1340+ AVIF_CHECKRES (avifCodecCreate (AVIF_CODEC_CHOICE_AUTO , AVIF_CODEC_FLAG_CAN_DECODE , codec ));
1341+ (* codec )-> diag = & encoder -> diag ;
1342+ AVIF_CHECKRES (avifImageCreateAllocate (decodedBaseImage , original , numBits , planes ));
1343+ avifBool isLimitedRangeAlpha = AVIF_FALSE ; // Ignored.
1344+ AVIF_CHECKERR ((* codec )-> getNextImage (* codec , & decoder , & sample , planes == AVIF_PLANES_A , & isLimitedRangeAlpha , * decodedBaseImage ),
1345+ AVIF_RESULT_ENCODE_SAMPLE_TRANSFORM_FAILED );
1346+ return AVIF_RESULT_OK ;
1347+ }
1348+
1349+ static avifResult avifEncoderCreateSatoImage (avifEncoder * encoder ,
13041350 const avifEncoderItem * item ,
13051351 avifBool itemWillBeEncodedLosslessly ,
13061352 const avifImage * image ,
@@ -1323,8 +1369,7 @@ static avifResult avifEncoderCreateSatoImage(const avifEncoder * encoder,
13231369 AVIF_CHECKRES (avifImageCreateAllocate (sampleTransformedImage , image , 8 , planes ));
13241370 AVIF_CHECKRES (avifImageApplyImgOpConst (* sampleTransformedImage , image , AVIF_SAMPLE_TRANSFORM_AND , 255 , planes ));
13251371 }
1326- } else {
1327- AVIF_CHECKERR (encoder -> sampleTransformRecipe == AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_EXTENSION_12B_4B , AVIF_RESULT_NOT_IMPLEMENTED );
1372+ } else if (encoder -> sampleTransformRecipe == AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_EXTENSION_12B_4B ) {
13281373 if (isBase ) {
13291374 AVIF_CHECKRES (avifImageCreateAllocate (sampleTransformedImage , image , 12 , planes ));
13301375 AVIF_CHECKRES (avifImageApplyImgOpConst (* sampleTransformedImage , image , AVIF_SAMPLE_TRANSFORM_DIVIDE , 16 , planes ));
@@ -1351,11 +1396,49 @@ static avifResult avifEncoderCreateSatoImage(const avifEncoder * encoder,
13511396 avifImageApplyImgOpConst (* sampleTransformedImage , * sampleTransformedImage , AVIF_SAMPLE_TRANSFORM_SUM , 7 , planes ));
13521397 }
13531398 }
1399+ } else {
1400+ AVIF_CHECKERR (encoder -> sampleTransformRecipe == AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_EXTENSION_12B_8B_OVERLAP_4B ,
1401+ AVIF_RESULT_NOT_IMPLEMENTED );
1402+ if (isBase ) {
1403+ AVIF_CHECKRES (avifImageCreateAllocate (sampleTransformedImage , image , 12 , planes ));
1404+ AVIF_CHECKRES (avifImageApplyImgOpConst (* sampleTransformedImage , image , AVIF_SAMPLE_TRANSFORM_DIVIDE , 16 , planes ));
1405+ } else {
1406+ AVIF_CHECKRES (avifImageCreateAllocate (sampleTransformedImage , image , 8 , planes ));
1407+ avifCodec * codec = NULL ;
1408+ avifImage * decodedBaseImage = NULL ;
1409+ avifResult result = avifEncoderDecodeSatoBaseImage (encoder , image , 12 , planes , & codec , & decodedBaseImage );
1410+ if (result == AVIF_RESULT_OK ) {
1411+ // decoded = main*16+hidden-128 so hidden = clamp_8b(original-main*16+128). Postfix notation.
1412+ const avifSampleTransformToken tokens [] = { { AVIF_SAMPLE_TRANSFORM_INPUT_IMAGE_ITEM_INDEX , 0 , /*inputImageItemIndex=*/ 1 },
1413+ { AVIF_SAMPLE_TRANSFORM_INPUT_IMAGE_ITEM_INDEX , 0 , /*inputImageItemIndex=*/ 2 },
1414+ { AVIF_SAMPLE_TRANSFORM_CONSTANT , /*constant=*/ 16 , 0 },
1415+ { AVIF_SAMPLE_TRANSFORM_PRODUCT , 0 , 0 },
1416+ { AVIF_SAMPLE_TRANSFORM_DIFFERENCE , 0 , 0 },
1417+ { AVIF_SAMPLE_TRANSFORM_CONSTANT , /*constant=*/ 128 , 0 },
1418+ { AVIF_SAMPLE_TRANSFORM_SUM , 0 , 0 } };
1419+ // image is "original" (index 1) and decodedBaseImage is "main" (index 2) in the formula above.
1420+ const avifImage * inputImageItems [] = { image , decodedBaseImage };
1421+ result = avifImageApplyOperations (* sampleTransformedImage ,
1422+ AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_32 ,
1423+ /*numTokens=*/ 7 ,
1424+ tokens ,
1425+ /*numInputImageItems=*/ 2 ,
1426+ inputImageItems ,
1427+ planes );
1428+ }
1429+ if (decodedBaseImage ) {
1430+ avifImageDestroy (decodedBaseImage );
1431+ }
1432+ if (codec ) {
1433+ avifCodecDestroy (codec );
1434+ }
1435+ AVIF_CHECKRES (result );
1436+ }
13541437 }
13551438 return AVIF_RESULT_OK ;
13561439}
13571440
1358- static avifResult avifEncoderCreateBitDepthExtensionImage (const avifEncoder * encoder ,
1441+ static avifResult avifEncoderCreateBitDepthExtensionImage (avifEncoder * encoder ,
13591442 const avifEncoderItem * item ,
13601443 avifBool itemWillBeEncodedLosslessly ,
13611444 const avifImage * image ,
@@ -1807,7 +1890,8 @@ static avifResult avifEncoderAddImageInternal(avifEncoder * encoder,
18071890
18081891#if defined(AVIF_ENABLE_EXPERIMENTAL_SAMPLE_TRANSFORM )
18091892 if (encoder -> sampleTransformRecipe == AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_EXTENSION_8B_8B ||
1810- encoder -> sampleTransformRecipe == AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_EXTENSION_12B_4B ) {
1893+ encoder -> sampleTransformRecipe == AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_EXTENSION_12B_4B ||
1894+ encoder -> sampleTransformRecipe == AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_EXTENSION_12B_8B_OVERLAP_4B ) {
18111895 // For now, only 16-bit depth is supported.
18121896 AVIF_ASSERT_OR_RETURN (firstCell -> depth == 16 );
18131897#if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP )
@@ -2655,7 +2739,8 @@ static avifResult avifRWStreamWriteProperties(avifItemPropertyDedup * const dedu
26552739 uint8_t depth = (uint8_t )itemMetadata -> depth ;
26562740#if defined(AVIF_ENABLE_EXPERIMENTAL_SAMPLE_TRANSFORM )
26572741 if (encoder -> sampleTransformRecipe == AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_EXTENSION_8B_8B ||
2658- encoder -> sampleTransformRecipe == AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_EXTENSION_12B_4B ) {
2742+ encoder -> sampleTransformRecipe == AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_EXTENSION_12B_4B ||
2743+ encoder -> sampleTransformRecipe == AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_EXTENSION_12B_8B_OVERLAP_4B ) {
26592744 if (item -> itemCategory == AVIF_ITEM_SAMPLE_TRANSFORM ) {
26602745 AVIF_ASSERT_OR_RETURN (depth == 16 ); // Only 16-bit depth is supported for now.
26612746 } else if (encoder -> sampleTransformRecipe == AVIF_SAMPLE_TRANSFORM_BIT_DEPTH_EXTENSION_8B_8B ) {
0 commit comments