From faa229453fe599b674eb05d1c3f81187fa887919 Mon Sep 17 00:00:00 2001 From: qbnu <93988953+qbnu@users.noreply.github.com> Date: Thu, 23 May 2024 19:52:09 -0400 Subject: [PATCH 1/4] Implement AVIF transformations --- src/JPEGView/AVIFWrapper.cpp | 40 ++++++++++++++++++++++++++++++++ src/JPEGView/BasicProcessing.cpp | 6 +++++ src/JPEGView/BasicProcessing.h | 3 +++ src/JPEGView/JPEGImage.cpp | 3 +-- 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/JPEGView/AVIFWrapper.cpp b/src/JPEGView/AVIFWrapper.cpp index eb19fa4a..fd89af4e 100644 --- a/src/JPEGView/AVIFWrapper.cpp +++ b/src/JPEGView/AVIFWrapper.cpp @@ -2,6 +2,7 @@ #include "AVIFWrapper.h" #include "avif/avif.h" +#include "BasicProcessing.h" #include "MaxImageDef.h" #include "ICCProfileTransform.h" @@ -106,6 +107,45 @@ void* AvifReader::ReadImage(int& width, } } + // Handle clap, irot and imir boxes + avifTransformFlags flags = cache.decoder->image->transformFlags; + if (flags & AVIF_TRANSFORM_CLAP) { + avifCleanApertureBox* clap = &cache.decoder->image->clap; + avifCropRect crop; + avifDiagnostics diag; + if (avifCropRectConvertCleanApertureBox(&crop, clap, width, height, cache.decoder->image->yuvFormat, &diag)) { + POINT point = { crop.x, crop.y }; + SIZE sz = { crop.width, crop.height }; + void* pixels = CBasicProcessing::Crop32bpp(width, height, cache.rgb.pixels, CRect(point, sz)); + if (pixels != NULL) { + delete[] cache.rgb.pixels; + cache.rgb.pixels = (uint8_t*)pixels; + width = crop.width; + height = crop.height; + } + } + } + if (flags & AVIF_TRANSFORM_IROT) { + int angle = 360 - cache.decoder->image->irot.angle * 90; + void* pixels = CBasicProcessing::Rotate32bpp(width, height, cache.rgb.pixels, angle); + if (pixels != NULL) { + delete[] cache.rgb.pixels; + cache.rgb.pixels = (uint8_t*)pixels; + if (angle != 180) { + int temp = width; + width = height; + height = temp; + } + } + } + if (flags & AVIF_TRANSFORM_IMIR) { + void* pixels = CBasicProcessing::Mirror32bpp(width, height, cache.rgb.pixels, cache.decoder->image->imir.axis); + if (pixels != NULL) { + delete[] cache.rgb.pixels; + cache.rgb.pixels = (uint8_t*)pixels; + } + } + void* pPixelData = cache.rgb.pixels; if (!has_animation) DeleteCache(); diff --git a/src/JPEGView/BasicProcessing.cpp b/src/JPEGView/BasicProcessing.cpp index bab24427..2f10db5a 100644 --- a/src/JPEGView/BasicProcessing.cpp +++ b/src/JPEGView/BasicProcessing.cpp @@ -654,6 +654,12 @@ void* CBasicProcessing::Rotate32bpp(int nWidth, int nHeight, const void* pDIBPix return pTarget; } +void* CBasicProcessing::Mirror32bpp(int nWidth, int nHeight, const void* pDIBPixels, bool bHorizontally) { + if (pDIBPixels == NULL) return NULL; + return bHorizontally ? CBasicProcessing::MirrorH32bpp(nWidth, nHeight, pDIBPixels) : + CBasicProcessing::MirrorV32bpp(nWidth, nHeight, pDIBPixels); +} + void* CBasicProcessing::MirrorH32bpp(int nWidth, int nHeight, const void* pDIBPixels) { uint32* pTarget = new(std::nothrow) uint32[nWidth * nHeight]; if (pTarget == NULL) return NULL; diff --git a/src/JPEGView/BasicProcessing.h b/src/JPEGView/BasicProcessing.h index 83cba2c7..92078ea1 100644 --- a/src/JPEGView/BasicProcessing.h +++ b/src/JPEGView/BasicProcessing.h @@ -56,6 +56,9 @@ class CBasicProcessing // cases the return value is NULL static void* Rotate32bpp(int nWidth, int nHeight, const void* pDIBPixels, int nRotationAngleCW); + // Mirror 32 bit DIB + static void* Mirror32bpp(int nWidth, int nHeight, const void* pDIBPixels, bool bHorizontally); + // Mirror 32 bit DIB horizontally static void* MirrorH32bpp(int nWidth, int nHeight, const void* pDIBPixels); diff --git a/src/JPEGView/JPEGImage.cpp b/src/JPEGView/JPEGImage.cpp index 5c465f06..1ec23f41 100644 --- a/src/JPEGView/JPEGImage.cpp +++ b/src/JPEGView/JPEGImage.cpp @@ -715,8 +715,7 @@ bool CJPEGImage::Mirror(bool bHorizontally) { } InvalidateAllCachedPixelData(); - void* pNewOriginalPixels = bHorizontally ? CBasicProcessing::MirrorH32bpp(m_nOrigWidth, m_nOrigHeight, m_pOrigPixels) : - CBasicProcessing::MirrorV32bpp(m_nOrigWidth, m_nOrigHeight, m_pOrigPixels); + void* pNewOriginalPixels = CBasicProcessing::Mirror32bpp(m_nOrigWidth, m_nOrigHeight, m_pOrigPixels, bHorizontally); if (pNewOriginalPixels == NULL) return false; delete[] m_pOrigPixels; m_pOrigPixels = pNewOriginalPixels; From 3da98525e355dd7d0604711ad344e102058c58e3 Mon Sep 17 00:00:00 2001 From: qbnu <93988953+qbnu@users.noreply.github.com> Date: Thu, 23 May 2024 21:00:07 -0400 Subject: [PATCH 2/4] move code block --- src/JPEGView/AVIFWrapper.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/JPEGView/AVIFWrapper.cpp b/src/JPEGView/AVIFWrapper.cpp index fd89af4e..d80c433a 100644 --- a/src/JPEGView/AVIFWrapper.cpp +++ b/src/JPEGView/AVIFWrapper.cpp @@ -92,20 +92,6 @@ void* AvifReader::ReadImage(int& width, DeleteCache(); return NULL; } - avifRWData icc = cache.decoder->image->icc; - if (cache.transform == NULL) - cache.transform = ICCProfileTransform::CreateTransform(icc.data, icc.size, ICCProfileTransform::FORMAT_BGRA); - ICCProfileTransform::DoTransform(cache.transform, cache.rgb.pixels, cache.rgb.pixels, width, height); - - avifRWData exif = cache.decoder->image->exif; - if (exif.size > 8 && exif.size < 65528 && exif.data != NULL) { - exif_chunk = malloc(exif.size + 10); - if (exif_chunk != NULL) { - memcpy(exif_chunk, "\xFF\xE1\0\0Exif\0\0", 10); - *((unsigned short*)exif_chunk + 1) = _byteswap_ushort(exif.size + 8); - memcpy((uint8_t*)exif_chunk + 10, exif.data, exif.size); - } - } // Handle clap, irot and imir boxes avifTransformFlags flags = cache.decoder->image->transformFlags; @@ -146,6 +132,21 @@ void* AvifReader::ReadImage(int& width, } } + avifRWData icc = cache.decoder->image->icc; + if (cache.transform == NULL) + cache.transform = ICCProfileTransform::CreateTransform(icc.data, icc.size, ICCProfileTransform::FORMAT_BGRA); + ICCProfileTransform::DoTransform(cache.transform, cache.rgb.pixels, cache.rgb.pixels, width, height); + + avifRWData exif = cache.decoder->image->exif; + if (exif.size > 8 && exif.size < 65528 && exif.data != NULL) { + exif_chunk = malloc(exif.size + 10); + if (exif_chunk != NULL) { + memcpy(exif_chunk, "\xFF\xE1\0\0Exif\0\0", 10); + *((unsigned short*)exif_chunk + 1) = _byteswap_ushort(exif.size + 8); + memcpy((uint8_t*)exif_chunk + 10, exif.data, exif.size); + } + } + void* pPixelData = cache.rgb.pixels; if (!has_animation) DeleteCache(); From dae157c872ae407f2f334d3a8a5586a3f86928aa Mon Sep 17 00:00:00 2001 From: qbnu <93988953+qbnu@users.noreply.github.com> Date: Thu, 23 May 2024 21:12:47 -0400 Subject: [PATCH 3/4] remove NULL check --- src/JPEGView/BasicProcessing.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/JPEGView/BasicProcessing.cpp b/src/JPEGView/BasicProcessing.cpp index 2f10db5a..e2903052 100644 --- a/src/JPEGView/BasicProcessing.cpp +++ b/src/JPEGView/BasicProcessing.cpp @@ -655,7 +655,6 @@ void* CBasicProcessing::Rotate32bpp(int nWidth, int nHeight, const void* pDIBPix } void* CBasicProcessing::Mirror32bpp(int nWidth, int nHeight, const void* pDIBPixels, bool bHorizontally) { - if (pDIBPixels == NULL) return NULL; return bHorizontally ? CBasicProcessing::MirrorH32bpp(nWidth, nHeight, pDIBPixels) : CBasicProcessing::MirrorV32bpp(nWidth, nHeight, pDIBPixels); } From c380b969e7a2406fc1678af9850e087d411cb882 Mon Sep 17 00:00:00 2001 From: qbnu <93988953+qbnu@users.noreply.github.com> Date: Sat, 25 May 2024 17:38:25 -0400 Subject: [PATCH 4/4] disable strict AVIF decoding --- src/JPEGView/AVIFWrapper.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/JPEGView/AVIFWrapper.cpp b/src/JPEGView/AVIFWrapper.cpp index d80c433a..9ea36ff1 100644 --- a/src/JPEGView/AVIFWrapper.cpp +++ b/src/JPEGView/AVIFWrapper.cpp @@ -47,6 +47,7 @@ void* AvifReader::ReadImage(int& width, memcpy(cache.data, buffer, sizebytes); cache.decoder = avifDecoderCreate(); cache.decoder->maxThreads = nthreads; + cache.decoder->strictFlags = AVIF_STRICT_DISABLED; result = avifDecoderSetIOMemory(cache.decoder, cache.data, sizebytes); if (result != AVIF_RESULT_OK) { DeleteCache();