[Tizen] Support CMYK jpg image load 34/287634/1
authorEunki, Hong <eunkiki.hong@samsung.com>
Wed, 1 Feb 2023 21:07:42 +0000 (06:07 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Wed, 1 Feb 2023 21:44:07 +0000 (06:44 +0900)
Previously, we only load CMYK image store as Pixel::RGBA8888 and do nothing.
So, We need to convert this 4byte data as 3byte Pixel::RGB888 format.

Change-Id: If3b2a1dc14f59b68bebe7c024164f5f7565aa26b
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
dali/internal/imaging/common/loader-jpeg-turbo.cpp

index f448d97..e95b312 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -472,6 +472,32 @@ void Rotate270(PixelArray buffer, int width, int height)
   }
 }
 
+/**
+ * @brief Helper function to convert from Turbo Jpeg Pixel Format as TJPF_CMYK to RGB888 by naive method.
+ *
+ * @param[in] cmykBuffer buffer of cmyk.
+ * @param[in] rgbBuffer buffer of Pixel::RGB888
+ * @param[in] width width of image.
+ * @param[in] height height of image.
+ */
+void ConvertTjpfCMYKToRGB888(PixelArray __restrict__ cmykBuffer, PixelArray __restrict__ rgbBuffer, int32_t width, int32_t height)
+{
+  const int32_t pixelCount = width * height;
+  const uint8_t cmykBpp    = 4u;
+  const uint8_t bpp        = 3u;
+
+  const PixelArray cmykBufferEnd = cmykBuffer + pixelCount * cmykBpp;
+  // Convert every pixel
+  while(cmykBuffer != cmykBufferEnd)
+  {
+    const uint16_t channelK = static_cast<uint16_t>(*(cmykBuffer + 3u));
+    *(rgbBuffer + 0u)      = static_cast<uint8_t>(static_cast<uint16_t>(*(cmykBuffer + 0u)) * channelK / 255);
+    *(rgbBuffer + 1u)      = static_cast<uint8_t>(static_cast<uint16_t>(*(cmykBuffer + 1u)) * channelK / 255);
+    *(rgbBuffer + 2u)      = static_cast<uint8_t>(static_cast<uint16_t>(*(cmykBuffer + 2u)) * channelK / 255);
+    cmykBuffer += cmykBpp;
+    rgbBuffer += bpp;
+  }
+}
 } // namespace
 
 namespace Dali
@@ -620,22 +646,12 @@ bool LoadBitmapFromJpeg( const Dali::ImageLoader::Input& input, Dali::Devel::Pix
   int chrominanceSubsampling = -1;
   int preXformImageWidth = 0, preXformImageHeight = 0;
 
-  // In Ubuntu, the turbojpeg version is not correct. so build error occurs.
-  // Temporarily separate Ubuntu and other profiles.
-#ifndef DALI_PROFILE_UBUNTU
   int jpegColorspace = -1;
   if( tjDecompressHeader3( jpeg.get(), jpegBufferPtr, jpegBufferSize, &preXformImageWidth, &preXformImageHeight, &chrominanceSubsampling, &jpegColorspace ) == -1 )
   {
     DALI_LOG_ERROR("%s\n", tjGetErrorStr());
     // Do not set width and height to 0 or return early as this sometimes fails only on determining subsampling type.
   }
-#else
-  if( tjDecompressHeader2( jpeg.get(), jpegBufferPtr, jpegBufferSize, &preXformImageWidth, &preXformImageHeight, &chrominanceSubsampling ) == -1 )
-  {
-    DALI_LOG_ERROR("%s\n", tjGetErrorStr());
-    // Do not set width and height to 0 or return early as this sometimes fails only on determining subsampling type.
-  }
-#endif
 
   if(preXformImageWidth == 0 || preXformImageHeight == 0)
   {
@@ -669,7 +685,6 @@ bool LoadBitmapFromJpeg( const Dali::ImageLoader::Input& input, Dali::Devel::Pix
   // Colorspace conversion options
   TJPF pixelLibJpegType = TJPF_RGB;
   Pixel::Format pixelFormat = Pixel::RGB888;
-#ifndef DALI_PROFILE_UBUNTU
   switch (jpegColorspace)
   {
     case TJCS_RGB:
@@ -691,7 +706,7 @@ bool LoadBitmapFromJpeg( const Dali::ImageLoader::Input& input, Dali::Devel::Pix
     case TJCS_YCCK:
     {
       pixelLibJpegType = TJPF_CMYK;
-      pixelFormat = Pixel::RGBA8888;
+      pixelFormat = Pixel::RGB888;
       break;
     }
     default:
@@ -701,7 +716,6 @@ bool LoadBitmapFromJpeg( const Dali::ImageLoader::Input& input, Dali::Devel::Pix
       break;
     }
   }
-#endif
   // Allocate a bitmap and decompress the jpeg buffer into its pixel buffer:
   bitmap = Dali::Devel::PixelBuffer::New(scaledPostXformWidth, scaledPostXformHeight, pixelFormat);
 
@@ -710,18 +724,49 @@ bool LoadBitmapFromJpeg( const Dali::ImageLoader::Input& input, Dali::Devel::Pix
 
   auto bitmapPixelBuffer = bitmap.GetBuffer();
 
-  if( tjDecompress2( jpeg.get(), jpegBufferPtr, jpegBufferSize, reinterpret_cast<unsigned char*>( bitmapPixelBuffer ), scaledPreXformWidth, 0, scaledPreXformHeight, pixelLibJpegType, flags ) == -1 )
+  if(pixelLibJpegType == TJPF_CMYK)
   {
-    std::string errorString = tjGetErrorStr();
+    // Currently we support only for 4 bytes per each CMYK pixel.
+    const uint8_t cmykBytesPerPixel = 4u;
+
+    uint8_t* cmykBuffer = static_cast<uint8_t*>(malloc(sizeof(uint8_t) * scaledPostXformWidth * scaledPostXformHeight * cmykBytesPerPixel));
 
-    if( IsJpegErrorFatal( errorString ) )
+    int decodeResult = tjDecompress2(jpeg.get(), jpegBufferPtr, jpegBufferSize, reinterpret_cast<uint8_t*>(cmykBuffer), scaledPreXformWidth, 0, scaledPreXformHeight, pixelLibJpegType, flags);
+    if(DALI_UNLIKELY(decodeResult == -1))
     {
-        DALI_LOG_ERROR("%s\n", errorString.c_str() );
+      std::string errorString = tjGetErrorStr();
+
+      if(IsJpegErrorFatal(errorString))
+      {
+        DALI_LOG_ERROR("%s\n", errorString.c_str());
+        free(cmykBuffer);
         return false;
+      }
+      else
+      {
+        DALI_LOG_WARNING("%s\n", errorString.c_str());
+      }
     }
-    else
+    ConvertTjpfCMYKToRGB888(cmykBuffer, bitmapPixelBuffer, scaledPostXformWidth, scaledPostXformHeight);
+
+    free(cmykBuffer);
+  }
+  else
+  {
+    int decodeResult = tjDecompress2(jpeg.get(), jpegBufferPtr, jpegBufferSize, reinterpret_cast<uint8_t*>(bitmapPixelBuffer), scaledPreXformWidth, 0, scaledPreXformHeight, pixelLibJpegType, flags);
+    if(DALI_UNLIKELY(decodeResult == -1))
     {
-        DALI_LOG_WARNING("%s\n", errorString.c_str() );
+      std::string errorString = tjGetErrorStr();
+
+      if(IsJpegErrorFatal(errorString))
+      {
+        DALI_LOG_ERROR("%s\n", errorString.c_str());
+        return false;
+      }
+      else
+      {
+        DALI_LOG_WARNING("%s\n", errorString.c_str());
+      }
     }
   }