TizenRefApp-7828 Implement resize of thumbnail 38/106738/16
authorIryna Ferenchak <i.ferenchak@samsung.com>
Thu, 19 Jan 2017 09:06:05 +0000 (11:06 +0200)
committerGerrit Code Review <gerrit@review.vlan103.tizen.org>
Thu, 19 Jan 2017 14:39:08 +0000 (06:39 -0800)
Change-Id: I1326fd430f1c46a24204fc1c458689090334e53b
Signed-off-by: Iryna Ferenchak <i.ferenchak@samsung.com>
lib-common/inc/Common/ImageData.h
lib-common/inc/Common/ImageUtils.h
lib-common/src/Common/ImageData.cpp
lib-common/src/Common/ImageUtils.cpp
memo-svc/src/Service/DataProvider.cpp

index 8fa7118cc52a7aca9922b68714c3b9446570e4e8..c686e6be70aa5a5c02c0ca266297d3e4a7ef54f4 100644 (file)
@@ -32,18 +32,15 @@ namespace Common
        typedef std::function<void(int error)> ResultCallback;
 
        /**
-       * @brief Implements useful image utils. Self removed.
+       * @brief Implements useful image utils.
         */
        class ImageData
        {
        public:
                /**
-                * @brief Create image data.
-                * @param[in]   origPath       Image path
-                * @param[in]   destPath       Destination path of cropped image.
-                * @param[in]   callback       Callback that is called when image is cropped.
+                @param[in]   path       Image path
                 */
-               ImageData(const char *origPath, const char *destPath, ResultCallback callback);
+               explicit ImageData(std::string path);
                ~ImageData();
 
                /**
@@ -52,36 +49,47 @@ namespace Common
                 */
                bool initialize();
 
+               /**
+                * @brief Export image to file.
+                * @param[in]   destPath       Destination path of image.
+                * @return true if success.
+                */
+               bool exportToFile(const char *destPath);
+
+               /**
+                * @brief Resize image.
+                * @param[in]   width          Width of resized image
+                * @param[in]   height         Height of resized image
+                * @param[in]   callback       Callback that is called when image is resized.
+                * @return true if success.
+                */
+               bool resize(unsigned long width, unsigned long height, ResultCallback callback);
+
                /**
                 * @brief Crop image.
                 * @param[in]   width          Width of cropped image
                 * @param[in]   height         Height of cropped image
+                * @param[in]   callback       Callback that is called when image is cropped.
                 * @return true if success.
                 */
-               bool crop(int width, int height);
+               bool crop(unsigned long width, unsigned long height, ResultCallback callback);
 
        private:
-               bool decode();
-               bool encode();
-               void createJpegFile(unsigned char *jpegBuffer);
+               double getResizeRatio(int width, int height);
+               void createPacket(unsigned char *buffer, unsigned long long bufferSize);
+               void createJpegFile(const char *destPath, unsigned char *jpegBuffer, unsigned long long bufferSize);
                image_util_rotation_e getRotation();
-               void onCropFinished(media_packet_h *dst, int error);
-
-               unsigned char *m_Buffer;
-               unsigned long long m_BufferSize;
+               void clear();
+               void onFinished(media_packet_h *dst, int error);
 
-               unsigned long m_OrigWidth;
-               unsigned long m_OrigHeight;
-               unsigned long m_DestWidth;
-               unsigned long m_DestHeight;
+               std::string m_Path;
 
-               std::string m_OrigPath;
-               std::string m_DestPath;
+               unsigned long m_Width;
+               unsigned long m_Height;
 
                ExifData *m_ExifData;
-               media_format_h m_Fmt;
                media_packet_h m_Packet;
-               ResultCallback m_OnCropped;
+               ResultCallback m_OnResult;
        };
 }
 
index b27b31de7674ea1124c6408a18f3e278d0283796..b6997e721251b009e1f0d447a2f905b0c216d8d2 100644 (file)
@@ -30,7 +30,7 @@ namespace Common
         * @param[in]   callback       Callback that is called when image is cropped
         * @return true if success.
         */
-       EXPORT_API bool cropImage(const char *origPath, int destWidth, int destHeight, const char *destPath, ResultCallback callback);
+       EXPORT_API bool cropImage(std::string origPath, int destWidth, int destHeight, std::string destPath, ResultCallback callback);
 }
 
 #endif /* COMMON_IMAGE_UTILS_H */
index 19c4b0b16d150f950233578bea3de25711078b4b..19a1ccb847817f4beae76c0cd67eb80a16fe8719 100644 (file)
@@ -27,135 +27,178 @@ const unsigned char EXIF_HEADER[] = { 0xff, 0xd8, 0xff, 0xe1 };
 const unsigned int EXIF_HEADER_LEN = sizeof(EXIF_HEADER);
 const unsigned int JPEG_HEADER_OFFSET = 20;
 
-ImageData::ImageData(const char *origPath, const char *destPath, ResultCallback callback)
-       : m_Buffer(nullptr),
-         m_BufferSize(0),
-         m_OrigWidth(0),
-         m_OrigHeight(0),
-         m_DestWidth(0),
-         m_DestHeight(0),
-         m_OrigPath(origPath),
-         m_DestPath(destPath),
+ImageData::ImageData(std::string path)
+       : m_Path(std::move(path)),
+         m_Width(0),
+         m_Height(0),
          m_ExifData(nullptr),
-         m_Fmt(nullptr),
-         m_Packet(nullptr),
-         m_OnCropped(std::move(callback))
+         m_Packet(nullptr)
 {
 }
 
 ImageData::~ImageData()
 {
-       exif_data_unref(m_ExifData);
-       media_packet_destroy(m_Packet);
+       clear();
 }
 
 bool ImageData::initialize()
 {
-       bool isSuccess = decode();
-       if (!isSuccess || m_Buffer == nullptr) {
-               free(m_Buffer);
-               m_Buffer = nullptr;
-               return false;
-       }
+       unsigned char *buffer = nullptr;
+       unsigned long long bufferSize = 0;
 
-       media_format_create(&m_Fmt);
-       media_format_set_video_mime(m_Fmt, MEDIA_FORMAT_RGBA);
-       media_format_set_video_width(m_Fmt, m_OrigWidth);
-       media_format_set_video_height(m_Fmt, m_OrigHeight);
+       m_ExifData = exif_data_new_from_file(m_Path.c_str());
 
-       void *srcPtr = nullptr;
-       media_packet_create_alloc(m_Fmt, nullptr, nullptr, &m_Packet);
-       media_packet_get_buffer_data_ptr(m_Packet, &srcPtr);
-       memcpy(srcPtr, m_Buffer, m_BufferSize);
-       free(m_Buffer);
-       m_Buffer = nullptr;
-       media_format_unref(m_Fmt);
+       image_util_decode_h decoder = nullptr;
+       image_util_decode_create(&decoder);
+       image_util_decode_set_input_path(decoder, m_Path.c_str());
+       image_util_decode_set_colorspace(decoder, IMAGE_UTIL_COLORSPACE_RGBA8888);
+       image_util_decode_set_output_buffer(decoder, &buffer);
+       int err = image_util_decode_run(decoder, &m_Width, &m_Height, &bufferSize);
 
-       return true;
+       WARN_IF_ERR(err, "image_util_decode_run() failed.");
+       image_util_decode_destroy(decoder);
+
+       bool isSuccess = (buffer && err == IMAGE_UTIL_ERROR_NONE);
+       if (isSuccess) {
+               createPacket(buffer, bufferSize);
+       } else {
+               clear();
+       }
+       free(buffer);
+
+       return isSuccess;
 }
 
-bool ImageData::crop(int width, int height)
+bool ImageData::exportToFile(const char *destPath)
 {
-       m_DestWidth = width;
-       m_DestHeight = height;
+       unsigned char *buffer = nullptr;
+       unsigned long long bufferSize = 0;
+       media_packet_get_buffer_data_ptr(m_Packet, (void **)&buffer);
+       media_packet_get_buffer_size(m_Packet, (uint64_t *)&bufferSize);
+
+       unsigned char *jpegBuffer = nullptr;
+       image_util_encode_h encoder = nullptr;
+
+       image_util_encode_create(IMAGE_UTIL_JPEG, &encoder);
+       image_util_encode_set_resolution(encoder, m_Width, m_Height);
+       image_util_encode_set_colorspace(encoder, IMAGE_UTIL_COLORSPACE_RGBA8888);
+       image_util_encode_set_quality(encoder, 100);
+       image_util_encode_set_input_buffer(encoder, buffer);
+       image_util_encode_set_output_buffer(encoder, &jpegBuffer);
+       int err = image_util_encode_run(encoder, nullptr);
 
+       WARN_IF_ERR(err, "image_util_encode_run() failed.");
+       image_util_encode_destroy(encoder);
+
+       if (err == IMAGE_UTIL_ERROR_NONE) {
+               createJpegFile(destPath, jpegBuffer, bufferSize);
+       }
+       free(jpegBuffer);
+
+       return err == IMAGE_UTIL_ERROR_NONE;
+}
+
+bool ImageData::resize(unsigned long width, unsigned long height, ResultCallback callback)
+{
+       if (callback == nullptr) {
+               return false;
+       }
        image_util_rotation_e rotation = getRotation();
+
        if (rotation == IMAGE_UTIL_ROTATION_90 || rotation == IMAGE_UTIL_ROTATION_270) {
-               std::swap(m_DestWidth, m_DestHeight);
+               std::swap(width, height);
        }
 
-       if (m_OrigWidth < m_DestWidth || m_OrigHeight < m_DestHeight) {
+       if (m_Width < width || m_Height < height) {
                return false;
        }
+       m_OnResult = std::move(callback);
 
-       transformation_h handle;
+       double ratio = getResizeRatio(width, height);
+
+       transformation_h handle = nullptr;
        image_util_transform_create(&handle);
        image_util_transform_set_hardware_acceleration(handle, true);
-       image_util_transform_set_crop_area(handle,
-                       (m_OrigWidth - m_DestWidth) / 2, (m_OrigHeight - m_DestHeight) / 2,
-                       (m_OrigWidth + m_DestWidth) / 2, (m_OrigHeight + m_DestHeight) / 2);
-       int err = image_util_transform_run(handle, m_Packet, makeCallbackWithLastParam(&ImageData::onCropFinished), this);
-       WARN_IF_ERR(err, "image_util_transform_run() failed.");
-
+       image_util_transform_set_resolution(handle, m_Width * ratio, m_Height * ratio);
+       int err = image_util_transform_run(handle, m_Packet, makeCallbackWithLastParam(&ImageData::onFinished), this);
+       if (err != IMAGE_UTIL_ERROR_NONE) {
+               m_OnResult = nullptr;
+               ERR("image_util_transform_run() failed.");
+               return false;
+       }
        return true;
 }
 
-bool ImageData::decode()
+bool ImageData::crop(unsigned long width, unsigned long height, ResultCallback callback)
 {
-       m_ExifData = exif_data_new_from_file(m_OrigPath.c_str());
+       if (callback == nullptr) {
+               return false;
+       }
+       image_util_rotation_e rotation = getRotation();
+       if (rotation == IMAGE_UTIL_ROTATION_90 || rotation == IMAGE_UTIL_ROTATION_270) {
+               std::swap(width, height);
+       }
 
-       image_util_decode_h decoder = nullptr;
-       image_util_decode_create(&decoder);
-       image_util_decode_set_input_path(decoder, m_OrigPath.c_str());
-       image_util_decode_set_colorspace(decoder, IMAGE_UTIL_COLORSPACE_RGBA8888);
-       image_util_decode_set_output_buffer(decoder, &m_Buffer);
-       int err = image_util_decode_run(decoder, &m_OrigWidth, &m_OrigHeight, &m_BufferSize);
-       WARN_IF_ERR(err, "image_util_decode_run() failed.");
-       image_util_decode_destroy(decoder);
+       if (m_Width < width || m_Height < height) {
+               return false;
+       }
 
-       return err == IMAGE_UTIL_ERROR_NONE;
+       m_OnResult = std::move(callback);
+       transformation_h handle = nullptr;
+       image_util_transform_create(&handle);
+       image_util_transform_set_hardware_acceleration(handle, true);
+       image_util_transform_set_crop_area(handle,
+               (m_Width - width) / 2, (m_Height - height) / 2,
+               (m_Width + width) / 2, (m_Height + height) / 2);
+       int err = image_util_transform_run(handle, m_Packet, makeCallbackWithLastParam(&ImageData::onFinished), this);
+       if (err != IMAGE_UTIL_ERROR_NONE) {
+               m_OnResult = nullptr;
+               ERR("image_util_transform_run() failed.");
+               return false;
+       }
+       return true;
 }
 
-bool ImageData::encode()
+double ImageData::getResizeRatio(int width, int height)
 {
-       unsigned char *jpegBuffer = nullptr;
-       image_util_encode_h encoder = nullptr;
+       double widthRatio = width / (double)m_Width;
+       double heightRatio = height / (double)m_Height;
+       return std::max(heightRatio, widthRatio);
+}
 
-       image_util_encode_create(IMAGE_UTIL_JPEG, &encoder);
-       image_util_encode_set_resolution(encoder, m_DestWidth, m_DestHeight);
-       image_util_encode_set_colorspace(encoder, IMAGE_UTIL_COLORSPACE_RGBA8888);
-       image_util_encode_set_quality(encoder, 100);
-       image_util_encode_set_input_buffer(encoder, m_Buffer);
-       image_util_encode_set_output_buffer(encoder, &jpegBuffer);
-       int err = image_util_encode_run(encoder, nullptr);
-       WARN_IF_ERR(err, "image_util_encode_run() failed.");
-       image_util_encode_destroy(encoder);
+void ImageData::createPacket(unsigned char *buffer, unsigned long long bufferSize)
+{
+       media_format_h fmt = nullptr;
+       media_format_create(&fmt);
+       media_format_set_video_mime(fmt, MEDIA_FORMAT_RGBA);
+       media_format_set_video_width(fmt, m_Width);
+       media_format_set_video_height(fmt, m_Height);
 
-       if (err == IMAGE_UTIL_ERROR_NONE) {
-               createJpegFile(jpegBuffer);
-       }
-       free(jpegBuffer);
+       void *srcPtr = nullptr;
+       media_packet_create_alloc(fmt, nullptr, nullptr, &m_Packet);
+       media_packet_get_buffer_data_ptr(m_Packet, &srcPtr);
+       memcpy(srcPtr, buffer, bufferSize);
 
-       return err == IMAGE_UTIL_ERROR_NONE;
+       media_format_unref(fmt);
 }
 
-void ImageData::createJpegFile(unsigned char *jpegBuffer)
+void ImageData::createJpegFile(const char *destPath, unsigned char *jpegBuffer, unsigned long long bufferSize)
 {
        unsigned char *exifBuff = nullptr;
        unsigned int exifBuffLen = 0;
        exif_data_save_data(m_ExifData, &exifBuff, &exifBuffLen);
 
        std::ofstream outputFile;
-       outputFile.open(m_DestPath.c_str());
+       outputFile.open(destPath);
        if(outputFile.is_open()) {
                if (exifBuff) {
                        outputFile.write((char *) EXIF_HEADER, EXIF_HEADER_LEN);
                        outputFile.put((exifBuffLen + 2) >> 8);
                        outputFile.put((exifBuffLen + 2) & 0xff);
                        outputFile.write((char *) exifBuff, exifBuffLen);
-                       outputFile.write((char *) jpegBuffer + JPEG_HEADER_OFFSET, m_BufferSize - JPEG_HEADER_OFFSET);
+                       outputFile.write((char *) jpegBuffer + JPEG_HEADER_OFFSET, bufferSize - JPEG_HEADER_OFFSET);
                } else {
-                       outputFile.write((char *)jpegBuffer, m_BufferSize);
+                       outputFile.write((char *)jpegBuffer, bufferSize);
                }
                outputFile.close();
        }
@@ -186,14 +229,30 @@ image_util_rotation_e ImageData::getRotation()
        return rotation;
 }
 
-void ImageData::onCropFinished(media_packet_h *dst, int error)
+void ImageData::clear()
 {
-       if (error == IMAGE_UTIL_ERROR_NONE) {
-               media_packet_get_buffer_data_ptr(*dst, (void **)&m_Buffer);
-               encode();
+       if (m_ExifData) {
+               exif_data_unref(m_ExifData);
+               m_ExifData = nullptr;
        }
-       if (m_OnCropped) {
-               m_OnCropped(error);
+       if (m_Packet) {
+               media_packet_destroy(m_Packet);
+               m_Packet = nullptr;
+       }
+}
+
+void ImageData::onFinished(media_packet_h *dst, int error)
+{
+       if (error == IMAGE_UTIL_ERROR_NONE) {
+               media_packet_destroy(m_Packet);
+               m_Packet = *dst;
+
+               media_format_h fmt = nullptr;
+               media_packet_get_format(m_Packet, &fmt);
+               media_format_get_video_info(fmt, nullptr, (int *)&m_Width, (int *)&m_Height, nullptr, nullptr);
        }
-       delete this;
+
+       ResultCallback callback = m_OnResult;
+       m_OnResult = nullptr;
+       callback(error);
 }
index cd380998f0d02fce763b1a35da33ec1560d7f201..51a4f33f2e8fc2c15d22fa9c3bd90eac5cf34369 100644 (file)
 #include "Utils/Callback.h"
 #include "Utils/Logger.h"
 
-bool Common::cropImage(const char *origPath, int destWidth, int destHeight, const char *destPath, ResultCallback callback)
+bool Common::cropImage(std::string origPath, int destWidth, int destHeight, std::string destPath, ResultCallback callback)
 {
-       if (origPath == nullptr || destPath == nullptr) {
-               return false;
-       }
-
-       ImageData *imageData = new ImageData(origPath, destPath, std::move(callback));
+       ImageData *imageData = new ImageData(std::move(origPath));
        bool isSuccess = imageData->initialize();
        if (isSuccess) {
-               isSuccess = imageData->crop(destWidth, destHeight);
+               isSuccess = imageData->resize(destWidth, destHeight, [imageData, callback, destPath, destWidth, destHeight](int error) {
+                       bool isSuccess = error == 0;
+                       if (isSuccess) {
+                               isSuccess = imageData->crop(destWidth, destHeight, [imageData, callback, destPath](int error) {
+                                       imageData->exportToFile(destPath.c_str());
+                                       callback(error);
+                                       delete imageData;
+                               });
+                       }
+                       if (!isSuccess) {
+                               callback(error);
+                               delete imageData;
+                       }
+               });
        }
+
        if (!isSuccess) {
                delete imageData;
        }
index 18c63282e6c8bd753951a7be89c8c2bd84b73ad9..8cf3f86352f787bad1e712e41f82f6b69b5e5fae 100644 (file)
@@ -382,8 +382,7 @@ void DataProvider::cropImage(sqlite3_context *context, int argc, sqlite3_value *
        std::string srcPath = Common::getFilePath(imageDir, srcName);
        std::string destPath = Common::getFilePath(thumbnailDir, srcName);
        int memoId = sqlite3_value_int(argv[1]);
-
-       bool isSuccess = Common::cropImage(srcPath.c_str(), CROP_WIDTH, CROP_HEIGHT, destPath.c_str(),
+       bool isSuccess = Common::cropImage(std::move(srcPath), CROP_WIDTH, CROP_HEIGHT, std::move(destPath),
                [provider, memoId](int error) {
                        provider->onSuccess(memoId);
                });