/*
- * Copyright (c) 2022 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.
// resolution: 2000*2560, pixel format: RGB888
const char* IMAGE_LARGE_EXIF3_RGB = TEST_RESOURCE_DIR "/f-large-exif-3.jpg";
+// resolution: 173*120, jpg color space: TJCS_CMYK, pixel format: RGB888
+const char* IMAGE_TJCS_CMYK = TEST_RESOURCE_DIR "/jpg_ycck_173x120.jpg";
+
// resolution: 128*128, pixel format: RGB888, YUV411
const char* IMAGE_128_YUV_411 = TEST_RESOURCE_DIR "/gallery-small-1-yuv411.jpg";
// resolution: 128*128, pixel format: RGB888, YUV420
DALI_TEST_EQUALS(pixelBufferJpeg.GetHeight(), 2560u, TEST_LOCATION);
DALI_TEST_EQUALS(pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION);
+ pixelBufferJpeg = Dali::LoadImageFromFile(IMAGE_TJCS_CMYK);
+ DALI_TEST_CHECK(pixelBufferJpeg);
+ DALI_TEST_EQUALS(pixelBufferJpeg.GetWidth(), 173u, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixelBufferJpeg.GetHeight(), 120u, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION);
+
Devel::PixelBuffer BufferJpeg1 = Dali::LoadImageFromFile(IMAGE_WIDTH_ODD_EXIF1_RGB);
DALI_TEST_CHECK(BufferJpeg1);
DALI_TEST_EQUALS(BufferJpeg1.GetWidth(), 55u, TEST_LOCATION);
DALI_TEST_EQUALS(pixelBufferJpeg.GetHeight(), 2560u, TEST_LOCATION);
DALI_TEST_EQUALS(pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION);
+ pixelBufferJpeg = Dali::LoadImageFromBuffer(FileToMemory(IMAGE_TJCS_CMYK));
+ DALI_TEST_CHECK(pixelBufferJpeg);
+ DALI_TEST_EQUALS(pixelBufferJpeg.GetWidth(), 173u, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixelBufferJpeg.GetHeight(), 120u, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION);
+
Devel::PixelBuffer BufferJpeg1 = Dali::LoadImageFromBuffer(FileToMemory(IMAGE_WIDTH_ODD_EXIF1_RGB));
DALI_TEST_CHECK(BufferJpeg1);
DALI_TEST_EQUALS(BufferJpeg1.GetWidth(), 55u, TEST_LOCATION);
/*
- * Copyright (c) 2022 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.
{
using Dali::Vector;
namespace Pixel = Dali::Pixel;
-using PixelArray = unsigned char*;
+using PixelArray = uint8_t*;
const unsigned int DECODED_L8 = 1;
const unsigned int DECODED_RGB888 = 3;
const unsigned int DECODED_RGBA8888 = 4;
return ExifHandle{nullptr, exif_data_free};
}
-ExifHandle MakeExifDataFromData(unsigned char* data, unsigned int size)
+ExifHandle MakeExifDataFromData(uint8_t* data, unsigned int size)
{
return ExifHandle{exif_data_new_from_data(data, size), exif_data_free};
}
return JpegHandle{tjInitDecompress(), tjDestroy};
}
-using JpegMemoryHandle = std::unique_ptr<unsigned char, decltype(tjFree)*>;
+using JpegMemoryHandle = std::unique_ptr<uint8_t, decltype(tjFree)*>;
JpegMemoryHandle MakeJpegMemory()
{
case TJCS_YCCK:
{
pixelLibJpegType = TJPF_CMYK;
- pixelFormat = Pixel::RGBA8888;
+ pixelFormat = Pixel::RGB888;
break;
}
default:
DALI_LOG_ERROR("Could not allocate temporary memory to hold JPEG file of size %uMB.\n", jpegBufferSize / 1048576U);
return false;
}
- unsigned char* const jpegBufferPtr = jpegBuffer.Begin();
+ uint8_t* const jpegBufferPtr = jpegBuffer.Begin();
// Pull the compressed JPEG image bytes out of a file and into memory:
if(DALI_UNLIKELY(fread(jpegBufferPtr, 1, jpegBufferSize, fp) != jpegBufferSize))
return true;
}
+/**
+ * @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 uint8_t channelK = *(cmykBuffer + 3u);
+ *(rgbBuffer + 0u) = Dali::Internal::Platform::MultiplyAndNormalizeColor(*(cmykBuffer + 0u), channelK);
+ *(rgbBuffer + 1u) = Dali::Internal::Platform::MultiplyAndNormalizeColor(*(cmykBuffer + 1u), channelK);
+ *(rgbBuffer + 2u) = Dali::Internal::Platform::MultiplyAndNormalizeColor(*(cmykBuffer + 2u), channelK);
+ cmykBuffer += cmykBpp;
+ rgbBuffer += bpp;
+ }
+}
} // namespace
namespace Dali
// Check decoding format
if(decodeToYuv && IsSubsamplingFormatEnabled(chrominanceSubsampling) && transform == JpegTransform::NONE)
{
- unsigned char* planes[3];
+ uint8_t* planes[3];
// Allocate buffers for each plane and decompress the jpeg buffer into the buffers
for(int i = 0; i < 3; i++)
{
auto planeSize = tjPlaneSizeYUV(i, scaledPostXformWidth, 0, scaledPostXformHeight, chrominanceSubsampling);
- unsigned char* buffer = static_cast<unsigned char*>(malloc(planeSize));
+ uint8_t* buffer = static_cast<uint8_t*>(malloc(planeSize));
if(!buffer)
{
DALI_LOG_ERROR("Buffer allocation is failed [%d]\n", planeSize);
const int flags = 0;
- int decodeResult = tjDecompressToYUVPlanes(jpeg.get(), jpegBufferPtr, jpegBufferSize, reinterpret_cast<unsigned char**>(&planes), scaledPostXformWidth, nullptr, scaledPostXformHeight, flags);
- if(decodeResult == -1 && IsJpegDecodingFailed())
+ int decodeResult = tjDecompressToYUVPlanes(jpeg.get(), jpegBufferPtr, jpegBufferSize, reinterpret_cast<uint8_t**>(&planes), scaledPostXformWidth, nullptr, scaledPostXformHeight, flags);
+ if(DALI_UNLIKELY(decodeResult == -1 && IsJpegDecodingFailed()))
{
pixelBuffers.clear();
return false;
auto bitmapPixelBuffer = bitmap.GetBuffer();
const int flags = 0;
- int decodeResult = tjDecompress2(jpeg.get(), jpegBufferPtr, jpegBufferSize, reinterpret_cast<unsigned char*>(bitmapPixelBuffer), scaledPreXformWidth, 0, scaledPreXformHeight, pixelLibJpegType, flags);
- if(decodeResult == -1 && IsJpegDecodingFailed())
+ int decodeResult = -1;
+ if(pixelLibJpegType == TJPF_CMYK)
{
- return false;
+ // 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));
+
+ decodeResult = tjDecompress2(jpeg.get(), jpegBufferPtr, jpegBufferSize, reinterpret_cast<uint8_t*>(cmykBuffer), scaledPreXformWidth, 0, scaledPreXformHeight, pixelLibJpegType, flags);
+ if(DALI_UNLIKELY(decodeResult == -1 && IsJpegDecodingFailed()))
+ {
+ free(cmykBuffer);
+ return false;
+ }
+ ConvertTjpfCMYKToRGB888(cmykBuffer, bitmapPixelBuffer, scaledPostXformWidth, scaledPostXformHeight);
+
+ free(cmykBuffer);
+ }
+ else
+ {
+ decodeResult = tjDecompress2(jpeg.get(), jpegBufferPtr, jpegBufferSize, reinterpret_cast<uint8_t*>(bitmapPixelBuffer), scaledPreXformWidth, 0, scaledPreXformHeight, pixelLibJpegType, flags);
+ if(DALI_UNLIKELY(decodeResult == -1 && IsJpegDecodingFailed()))
+ {
+ return false;
+ }
}
pixelBuffers.push_back(bitmap);
return result;
}
-bool EncodeToJpeg(const unsigned char* const pixelBuffer, Vector<unsigned char>& encodedPixels, const std::size_t width, const std::size_t height, const Pixel::Format pixelFormat, unsigned quality)
+bool EncodeToJpeg(const uint8_t* const pixelBuffer, Vector<uint8_t>& encodedPixels, const std::size_t width, const std::size_t height, const Pixel::Format pixelFormat, unsigned quality)
{
- if(!pixelBuffer)
+ if(DALI_UNLIKELY(!pixelBuffer))
{
DALI_LOG_ERROR("Null input buffer\n");
return false;
const int flags = 0;
if(DALI_UNLIKELY(tjCompress2(jpeg.get(),
- const_cast<unsigned char*>(pixelBuffer),
+ const_cast<uint8_t*>(pixelBuffer),
width,
0,
height,
ExifHandle LoadExifData(FILE* fp)
{
- auto exifData = MakeNullExifData();
- unsigned char dataBuffer[1024];
+ auto exifData = MakeNullExifData();
+ uint8_t dataBuffer[1024];
if(DALI_UNLIKELY(fseek(fp, 0, SEEK_SET)))
{
int postXformImageHeight = headerHeight;
success = TransformSize(requiredWidth, requiredHeight, input.scalingParameters.scalingMode, input.scalingParameters.samplingMode, transform, preXformImageWidth, preXformImageHeight, postXformImageWidth, postXformImageHeight);
- if(success)
+ if(DALI_LIKELY(success))
{
headerWidth = postXformImageWidth;
headerHeight = postXformImageHeight;