From: Vineeth TM Date: Wed, 18 Nov 2015 03:02:39 +0000 (+0900) Subject: image-util: Add decoding/encoding utilites for GIF,PNG X-Git-Tag: submit/tizen/20151118.234340^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F11%2F52011%2F1;p=platform%2Fcore%2Fapi%2Fimage-util.git image-util: Add decoding/encoding utilites for GIF,PNG Change-Id: I9fd2e400bd260d18fcf83aeda481bba978fe9803 Signed-off-by: Vineeth TM --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a85ffb..748afa4 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ SET(service "media") SET(submodule "image-util") # for package file -SET(dependents "dlog mmutil-jpeg mmutil-imgp mmutil-imgcv capi-base-common capi-media-tool") +SET(dependents "dlog mmutil-gif mmutil-png mmutil-jpeg mmutil-imgp mmutil-imgcv capi-base-common capi-media-tool") SET(pc_dependents "dlog capi-base-common capi-media-tool") SET(fw_name "${project_prefix}-${service}-${submodule}") @@ -92,6 +92,7 @@ CONFIGURE_FILE( INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) #ADD_SUBDIRECTORY(test) +ADD_SUBDIRECTORY(decode-test) IF(UNIX) diff --git a/decode-test/CMakeLists.txt b/decode-test/CMakeLists.txt new file mode 100755 index 0000000..82f0cad --- /dev/null +++ b/decode-test/CMakeLists.txt @@ -0,0 +1,21 @@ +SET(fw_test "${fw_name}-decode-test") + +INCLUDE(FindPkgConfig) +pkg_check_modules(${fw_test} REQUIRED glib-2.0) + +FOREACH(flag ${${fw_test}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") + MESSAGE(${flag}) +ENDFOREACH() + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -pie -Wall") + +aux_source_directory(. sources) +FOREACH(src ${sources}) + GET_FILENAME_COMPONENT(src_name ${src} NAME_WE) + MESSAGE("${src_name}") + ADD_EXECUTABLE(${fw_test} ${src}) + TARGET_LINK_LIBRARIES(${fw_test} ${fw_name} ${${fw_test}_LDFLAGS}) +ENDFOREACH() + +INSTALL(TARGETS ${fw_test} DESTINATION bin) diff --git a/decode-test/image_util_decode_encode_testsuite.c b/decode-test/image_util_decode_encode_testsuite.c new file mode 100755 index 0000000..fc7b912 --- /dev/null +++ b/decode-test/image_util_decode_encode_testsuite.c @@ -0,0 +1,295 @@ +/* + * image-utility + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Vineeth T M + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DECODE_RESULT_PATH "/media/decode_test." +#define BUFFER_SIZE 128 + +unsigned long image_width = 0, image_height = 0; +unsigned long long image_size = 0; + +GCond g_thread_cond; +GMutex g_thread_mutex; + +void _wait() +{ + g_mutex_lock(&g_thread_mutex); + fprintf(stderr, "waiting... until finishing \n"); + g_cond_wait(&g_thread_cond, &g_thread_mutex); + fprintf(stderr, "<=== get signal from callback \n"); + g_mutex_unlock(&g_thread_mutex); +} + +void _signal() +{ + g_mutex_lock(&g_thread_mutex); + g_cond_signal(&g_thread_cond); + fprintf(stderr, "===> send signal to test proc \n"); + g_mutex_unlock(&g_thread_mutex); +} + +static inline void flush_stdin() +{ + int ch; + while ((ch = getchar()) != EOF && ch != '\n') ; +} + +static int _read_file(char *file_name, void **data, unsigned long long *data_size) +{ + FILE *fp = NULL; + long file_size = 0; + + if (!file_name || !data || !data_size) { + fprintf(stderr, "\tNULL pointer\n"); + return FALSE; + } + + fprintf(stderr, "\tTry to open %s to read\n", file_name); + + fp = fopen(file_name, "r"); + if (fp == NULL) { + fprintf(stderr, "\tfile open failed %d\n", errno); + return FALSE; + } + + fseek(fp, 0, SEEK_END); + file_size = ftell(fp); + if (file_size > -1L) { + rewind(fp); + *data = (void *)malloc(file_size); + if (*data == NULL) { + fprintf(stderr, "\tmalloc failed %d\n", errno); + fclose(fp); + fp = NULL; + return FALSE; + } else { + if (fread(*data, 1, file_size, fp)) { + fprintf(stderr, "#Success# fread\n"); + } else { + fprintf(stderr, "#Error# fread\n"); + fclose(fp); + fp = NULL; + return FALSE; + } + } + fclose(fp); + fp = NULL; + + if (*data) { + *data_size = file_size; + return TRUE; + } else { + *data_size = 0; + return FALSE; + } + } else { + fprintf(stderr, "#Error# ftell\n"); + fclose(fp); + fp = NULL; + return FALSE; + } +} + +static int _write_file(const char *file_name, void *data, unsigned long long data_size) +{ + FILE *fp = NULL; + + if (!file_name || !data || data_size <= 0) { + fprintf(stderr, "\tinvalid data %s %p size:%lld\n", file_name, data, data_size); + return FALSE; + } + + fprintf(stderr, "\tTry to open %s to write\n", file_name); + + fp = fopen(file_name, "w"); + if (fp == NULL) { + fprintf(stderr, "\tfile open failed %d\n", errno); + return FALSE; + } + + fwrite(data, 1, data_size, fp); + fclose(fp); + fp = NULL; + + fprintf(stderr, "\tfile [%s] write DONE\n", file_name); + + return TRUE; +} + +bool decode_completed_cb(int error, void *user_param, unsigned long width, unsigned long height, unsigned long long size) +{ + image_width = width; + image_height = height; + _signal(); + + return TRUE; +} + +bool encode_completed_cb(int error, void *user_param, unsigned long long size) +{ + image_size = size; + _signal(); + + return TRUE; +} + +int main(int argc, char *argv[]) +{ + int ret = 0; + image_util_decode_h decoded = NULL; + image_util_encode_h encoded = NULL; + void *src = NULL; + unsigned char *data = NULL; + unsigned char *dst = NULL; + unsigned long long src_size = 0; + int image_type = -1; + int encode_image_type = -1; + + if (argc < 4) { + fprintf(stderr, "\t[usage]\n"); + fprintf(stderr, "\t\t1. decode : mm_util_png_testsuite decode image_type filepath encode_image_type\n"); + return 0; + } + + image_type = atoi(argv[2]); + if(argv[4]) + encode_image_type = atoi(argv[4]); + else + encode_image_type = atoi(argv[2]); + + if (!strcmp("decode", argv[1]) || !strcmp("decode-mem", argv[1]) || !strcmp("decode-async", argv[1])) { + ret = image_util_decode_create(image_type, &decoded); + if (ret != IMAGE_UTIL_ERROR_NONE) + return 0; + + if (!strcmp("decode", argv[1])) { + ret = image_util_decode_set_input_path(decoded, argv[3]); + if (ret != IMAGE_UTIL_ERROR_NONE) + return 0; + } else { + if (_read_file(argv[3], &src, &src_size)) + image_util_decode_set_input_buffer(decoded, (unsigned char *)src, src_size); + else + return 0; + } + ret = image_util_decode_set_output_buffer(decoded, &data); + if (ret != IMAGE_UTIL_ERROR_NONE) + return 0; + + if(!strcmp("decode-async", argv[1])) + { + ret = image_util_decode_run_async(decoded, (image_util_decode_completed_cb) decode_completed_cb, NULL); + _wait(); + } + else + ret = image_util_decode_run(decoded, &image_width, &image_height, NULL); + if (ret != IMAGE_UTIL_ERROR_NONE) + return 0; + + + + ret = image_util_decode_destroy(decoded); + if (ret != IMAGE_UTIL_ERROR_NONE) + return 0; + free(src); + } else { + fprintf(stderr, "\tunknown command [%s]\n", argv[1]); + return 0; + } + + if (ret != IMAGE_UTIL_ERROR_NONE) { + fprintf(stderr, "\tERROR is occurred %x\n", ret); + } else { + fprintf(stderr, "\tIMAGE OPERATION SUCCESS\n"); + if (data) { + fprintf(stderr, "\t##Decoded data##: %p\t width: %lu\t height:%lu\n", data, (long unsigned int)image_width, (long unsigned int)image_height); + char filename[BUFFER_SIZE] = { 0, }, type[4] = { + 0,}; + memset(filename, 0, BUFFER_SIZE); + + switch (encode_image_type) { + case IMAGE_UTIL_PNG: + snprintf(type, 4, "%s", "png"); + break; + case IMAGE_UTIL_GIF: + snprintf(type, 4, "%s", "gif"); + break; + default: + break; + } + snprintf(filename, BUFFER_SIZE, "%s%s", DECODE_RESULT_PATH, type); + + ret = image_util_encode_create(encode_image_type, &encoded); + if (ret != IMAGE_UTIL_ERROR_NONE) + return 0; + + ret = image_util_encode_set_resolution(encoded, image_width, image_height); + if (ret != IMAGE_UTIL_ERROR_NONE) + return 0; + + ret = image_util_encode_set_input_buffer(encoded, data); + if (ret != IMAGE_UTIL_ERROR_NONE) + return 0; + + if (!strcmp("decode-mem", argv[1])) { + ret = image_util_encode_set_output_buffer(encoded, &dst); + if (ret != IMAGE_UTIL_ERROR_NONE) + return 0; + } else { + ret = image_util_encode_set_output_path(encoded, filename); + if (ret != IMAGE_UTIL_ERROR_NONE) + return 0; + } + + if(!strcmp("decode-async", argv[1])) + { + ret = image_util_encode_run_async(encoded, (image_util_encode_completed_cb) encode_completed_cb, NULL); + _wait(); + } + else + ret = image_util_encode_run(encoded, &image_size); + if (ret != IMAGE_UTIL_ERROR_NONE) + return 0; + + if (!strcmp("decode-mem", argv[1])) { + _write_file(filename, (void *)dst, image_size); + free(dst); + } + + ret = image_util_encode_destroy(encoded); + if (ret != IMAGE_UTIL_ERROR_NONE) + return 0; + + free(data); + } else { + fprintf(stderr, "\tDECODED data is NULL\n"); + } + } + return 0; +} diff --git a/include/image_util.h b/include/image_util.h index 21921ee..bdfaa51 100755 --- a/include/image_util.h +++ b/include/image_util.h @@ -751,6 +751,485 @@ int image_util_encode_jpeg_to_memory(const unsigned char *image_buffer, int widt */ int image_util_extract_color_from_memory(const unsigned char *image_buffer, int width, int height, unsigned char *rgb_r, unsigned char *rgb_g, unsigned char *rgb_b); +/** +* @brief Creates a handle to image util decoding. +* @since_tizen 3.0 +* +* @details This function creates a handle to image util decoding. +* +* @remarks You must release the @a image util handle using image_util_decode_destroy(). +* +* @param[in] image_type The type of image for which to create decode handle. +* @param[out] handle A handle to image util decoding +* +* @return @c 0 on success, +* otherwise a negative error value +* +* @retval #IMAGE_UTIL_ERROR_NONE Successful +* @retval #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #IMAGE_UTIL_ERROR_OUT_OF_MEMORY Out of memory +* +* @see image_util_decode_destroy() +* +*/ +int image_util_decode_create(image_util_type_e image_type, image_util_decode_h *handle); + +/** +* @brief Sets the input file path from which to decode. +* @since_tizen 3.0 +* +* @remarks One of image_util_decode_set_input_path() or image_util_decode_set_input_buffer() should be set.\n +* If both are set then the latest input set, is considered.\n +* http://tizen.org/privilege/mediastorage is needed if input or output path are relevant to media storage.\n +* http://tizen.org/privilege/externalstorage is needed if input or output path are relevant to external storage. +* +* @param[in] handle The handle to image util decoding +* @param[in] path The path to input image +* +* @return @c 0 on success, +* otherwise a negative error value +* +* @retval #IMAGE_UTIL_ERROR_NONE Successful +* @retval #IMAGE_UTIL_ERROR_NO_SUCH_FILE No such file +* @retval #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #IMAGE_UTIL_ERROR_INVALID_OPERATION Invalid operation +* @retval #IMAGE_UTIL_ERROR_PERMISSION_DENIED The application does not have the privilege to call this funtion +* +* @pre image_util_decode_create() +* +* @post image_util_decode_run()/image_util_decode_run_async() +* @post image_util_decode_destroy() +* +* @see image_util_decode_create() +* @see image_util_decode_set_output_buffer() +* @see image_util_decode_run() +* @see image_util_decode_run_async() +* @see image_util_decode_destroy() +*/ +int image_util_decode_set_input_path(image_util_decode_h handle, const char *path); + +/** +* @brief Sets the input buffer from which to decode. +* @since_tizen 3.0 +* +* @remarks One of image_util_decode_set_input_path() or image_util_decode_set_input_buffer() should be set.\n +* If both are set then the latest input set, is considered. +* +* @param[in] handle The handle to image util decoding +* @param[in] src_buffer The input image buffer +* @param[in] src_size The input image buffer size +* +* @return @c 0 on success, +* otherwise a negative error value +* +* @retval #IMAGE_UTIL_ERROR_NONE Successful +* @retval #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #IMAGE_UTIL_ERROR_INVALID_OPERATION Invalid operation +* +* @pre image_util_decode_create() +* +* @post image_util_decode_run()/image_util_decode_run_async() +* @post image_util_decode_destroy() +* +* @see image_util_decode_create() +* @see image_util_decode_set_output_buffer() +* @see image_util_decode_run() +* @see image_util_decode_run_async() +* @see image_util_decode_destroy() +*/ +int image_util_decode_set_input_buffer(image_util_decode_h handle, const unsigned char *src_buffer, unsigned long long src_size); + +/** +* @brief Sets the output buffer to which the decoded buffer will be written to. +* @since_tizen 3.0 +* +* @remarks Either image_util_decode_set_input_path() or image_util_decode_set_input_buffer() should be set.\n +* The decoded output buffer will be RGBA format. +* +* @param[in] handle The handle to image util decoding +* @param[in] dst_buffer The decoded output buffer +* +* @return @c 0 on success, +* otherwise a negative error value +* +* @retval #IMAGE_UTIL_ERROR_NONE Successful +* @retval #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #IMAGE_UTIL_ERROR_INVALID_OPERATION Invalid operation +* +* @pre image_util_decode_create() +* +* @post image_util_decode_run()/image_util_decode_run_async() +* @post image_util_decode_destroy() +* +* @see image_util_decode_create() +* @see image_util_decode_set_input_path() +* @see image_util_decode_set_input_buffer() +* @see image_util_decode_run() +* @see image_util_decode_run_async() +* @see image_util_decode_destroy() +*/ +int image_util_decode_set_output_buffer(image_util_decode_h handle, unsigned char **dst_buffer); + +/** +* @brief Starts decoding of the image and fills the output buffer set using image_util_decode_set_output_buffer(). +* @since_tizen 3.0 +* +* @remarks The output will be stored in the pointer set using image_util_decode_set_output_buffer(). +* The function executes synchronously. +* +* @param[in] handle The handle to image util decoding +* @param[out] width Width of the decoded image +* @param[out] height Height of the decoded image +* @param[out] size Size of the decoded image +* +* @return @c 0 on success, +* otherwise a negative error value +* +* @retval #IMAGE_UTIL_ERROR_NONE Successful +* @retval #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #IMAGE_UTIL_ERROR_INVALID_OPERATION Invalid operation +* +* @pre image_util_decode_create() +* @pre image_util_decode_set_input_buffer()/image_util_decode_set_input_path(). +* @pre image_util_decode_set_output_buffer() +* +* @post image_util_decode_destroy() +* +* @see image_util_decode_create() +* @see image_util_decode_set_input_path() +* @see image_util_decode_set_input_buffer() +* @see image_util_decode_set_output_buffer() +* @see image_util_decode_destroy() +*/ +int image_util_decode_run(image_util_decode_h handle, unsigned long *width, unsigned long *height, unsigned long long *size); + +/** +* @brief Starts decoding of the image and fills the output buffer set using image_util_decode_set_output_buffer(). +* @since_tizen 3.0 +* +* @remarks The output will be stored in the pointer set using image_util_decode_set_output_buffer().\n +* The function executes asynchronously, which contains complete callback. +* +* @param[in] handle The handle to image util decoding +* @param[in] callback The callback function to be invoked +* @param[in] user_data The user data to be passed to the callback function +* +* @return @c 0 on success, +* otherwise a negative error value +* +* @retval #IMAGE_UTIL_ERROR_NONE Successful +* @retval #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #IMAGE_UTIL_ERROR_INVALID_OPERATION Invalid operation +* +* @pre image_util_decode_create() +* @pre image_util_decode_set_input_buffer()/image_util_decode_set_input_path(). +* @pre image_util_decode_set_output_buffer() +* +* @post image_util_decode_destroy() +* +* @see image_util_decode_create() +* @see image_util_decode_set_input_path() +* @see image_util_decode_set_input_buffer() +* @see image_util_decode_set_output_buffer() +* @see image_util_decode_destroy() +*/ +int image_util_decode_run_async(image_util_decode_h handle, image_util_decode_completed_cb callback, void *user_data); + +/** +* @brief Destroys the image decoding handle. +* @since_tizen 3.0 +* +* @remarks Any image handle created should be destroyed. +* +* @param[in] handle The handle to image util decoding +* +* @return @c 0 on success, +* otherwise a negative error value +* +* @retval #IMAGE_UTIL_ERROR_NONE Successful +* @retval #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #IMAGE_UTIL_ERROR_INVALID_OPERATION Invalid operation +* +* @pre image_util_decode_create() +* +* @see image_util_decode_create() +*/ +int image_util_decode_destroy(image_util_decode_h handle); + +/** +* @brief Creates a handle to image util encoding. +* @since_tizen 3.0 +* +* @details This function creates a handle to image util encoding. +* +* @remarks You must release the @a image util handle using image_util_encode_destroy(). +* +* @param[in] image_type The type of image for which to create encode handle. +* @param[out] handle A handle to image util encoding +* +* @return @c 0 on success, +* otherwise a negative error value +* +* @retval #IMAGE_UTIL_ERROR_NONE Successful +* @retval #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #IMAGE_UTIL_ERROR_OUT_OF_MEMORY Out of memory +* +* @see image_util_encode_destroy() +* +*/ +int image_util_encode_create(image_util_type_e image_type, image_util_encode_h *handle); + +/** +* @brief Sets the resolution of the encoded image. +* @since_tizen 3.0 +* +* @remarks This should be called before calling image_util_encode_run(). +* +* @param[in] handle The handle to image util encoding +* @param[in] width Width of the original image +* @param[in] height Height of the original image +* +* @return @c 0 on success, +* otherwise a negative error value +* +* @retval #IMAGE_UTIL_ERROR_NONE Successful +* @retval #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #IMAGE_UTIL_ERROR_INVALID_OPERATION Invalid operation +* +* @pre image_util_encode_create() +* +* @post image_util_encode_run()/image_util_encode_run_async() +* @post image_util_encode_destroy() +* +* @see image_util_encode_create() +* @see image_util_encode_set_input_buffer() +* @see image_util_encode_set_output_path() +* @see image_util_encode_set_output_buffer() +* @see image_util_encode_run() +* @see image_util_encode_run_async() +* @see image_util_encode_destroy() +*/ +int image_util_encode_set_resolution(image_util_encode_h handle, unsigned long width, unsigned long height); + +/** +* @brief Sets the compression value of png image encoding(0~9). +* @since_tizen 3.0 +* +* @remarks If application does not set this, then default compression of 6 is set. +* +* @param[in] handle The handle to image util encoding +* @param[in] compression The compression value valid from 0~9 +* +* @return @c 0 on success, +* otherwise a negative error value +* +* @retval #IMAGE_UTIL_ERROR_NONE Successful +* @retval #IMAGE_UTIL_ERROR_NOT_SUPPORTED_FORMAT Format not supported +* @retval #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #IMAGE_UTIL_ERROR_INVALID_OPERATION Invalid operation +* +* @pre image_util_encode_create() +* +* @post image_util_encode_run()/image_util_encode_run_async() +* @post image_util_encode_destroy() +* +* @see image_util_encode_create() +* @see image_util_encode_set_resolution() +* @see image_util_encode_set_input_buffer() +* @see image_util_encode_set_output_path() +* @see image_util_encode_set_output_buffer() +* @see image_util_encode_run() +* @see image_util_encode_run_async() +* @see image_util_encode_destroy() +*/ +int image_util_encode_set_png_compression(image_util_encode_h handle, image_util_png_compression_e compression); + +/** +* @brief Sets the input buffer from which to encode. +* @since_tizen 3.0 +* +* @remarks Either image_util_encode_set_output_path() or image_util_encode_set_output_buffer() should be set. +* The input buffer should be RGBA format. +* +* @param[in] handle The handle to image util decoding +* @param[in] src_buffer The input image buffer +* +* @return @c 0 on success, +* otherwise a negative error value +* +* @retval #IMAGE_UTIL_ERROR_NONE Successful +* @retval #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #IMAGE_UTIL_ERROR_INVALID_OPERATION Invalid operation +* +* @pre image_util_encode_create() +* +* @post image_util_encode_run()/image_util_encode_run_async() +* @post image_util_encode_destroy() +* +* @see image_util_encode_create() +* @see image_util_encode_set_resolution() +* @see image_util_encode_set_input_buffer() +* @see image_util_encode_set_output_path() +* @see image_util_encode_set_output_buffer() +* @see image_util_encode_run() +* @see image_util_encode_run_async() +* @see image_util_encode_destroy() +*/ +int image_util_encode_set_input_buffer(image_util_encode_h handle, const unsigned char *src_buffer); + +/** +* @brief Sets the output path to which to encoded buffer will be written to. +* @since_tizen 3.0 +* +* @remarks One of image_util_encode_set_output_path() or image_util_encode_set_output_buffer() should be set.\n +* If both are set then the latest output set is considered.\n +* http://tizen.org/privilege/mediastorage is needed if input or output path are relevant to media storage.\n +* http://tizen.org/privilege/externalstorage is needed if input or output path are relevant to external storage. +* +* @param[in] handle The handle to image util encoding +* @param[in] path The output file path +* +* @return @c 0 on success, +* otherwise a negative error value +* +* @retval #IMAGE_UTIL_ERROR_NONE Successful +* @retval #IMAGE_UTIL_ERROR_NO_SUCH_FILE No such file +* @retval #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #IMAGE_UTIL_ERROR_INVALID_OPERATION Invalid operation +* @retval #IMAGE_UTIL_ERROR_PERMISSION_DENIED The application does not have the privilege to call this funtion +* +* @pre image_util_encode_create() +* +* @post image_util_encode_run()/image_util_encode_run_async() +* @post image_util_encode_destroy() +* +* @see image_util_encode_create() +* @see image_util_encode_set_resolution() +* @see image_util_encode_set_input_buffer() +* @see image_util_encode_run() +* @see image_util_encode_run_async() +* @see image_util_encode_destroy() +*/ +int image_util_encode_set_output_path(image_util_encode_h handle, const char *path); + +/** +* @brief Sets the output buffer to which to encoded buffer will be written to. +* @since_tizen 3.0 +* +* @remarks One of image_util_encode_set_output_path() or image_util_encode_set_output_buffer() should be set.\n +* If both are set then the latest output set is considered. +* +* @param[in] handle The handle to image util encoding +* @param[in] dst_buffer The output image buffer +* +* @return @c 0 on success, +* otherwise a negative error value +* +* @retval #IMAGE_UTIL_ERROR_NONE Successful +* @retval #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #IMAGE_UTIL_ERROR_INVALID_OPERATION Invalid operation +* +* @pre image_util_encode_create() +* +* @post image_util_encode_run()/image_util_encode_run_async() +* @post image_util_encode_destroy() +* +* @see image_util_encode_create() +* @see image_util_encode_set_resolution() +* @see image_util_encode_set_input_buffer() +* @see image_util_encode_run() +* @see image_util_encode_run_async() +* @see image_util_encode_destroy() +*/ +int image_util_encode_set_output_buffer(image_util_encode_h handle, unsigned char **dst_buffer); + +/** +* @brief Starts encoding of the image and fills the output buffer, set using image_util_encode_set_output_buffer() or image_util_encode_set_output_path(). +* @since_tizen 3.0 +* +* @remarks The output will be stored in the pointer set to image_util_encode_set_output_buffer() or image_util_encode_set_output_path(). +* The function executes synchronously. +* +* @param[in] handle The handle to image util encoding +* @param[out] size Size of the encoded image +* +* @return @c 0 on success, +* otherwise a negative error value +* +* @retval #IMAGE_UTIL_ERROR_NONE Successful +* @retval #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #IMAGE_UTIL_ERROR_INVALID_OPERATION Invalid operation +* +* @pre image_util_encode_create() +* @pre image_util_encode_set_resolution() +* @pre image_util_encode_set_input_buffer() +* @pre image_util_encode_set_output_buffer()/image_util_encode_set_output_path() +* +* @post image_util_encode_destroy() +* +* @see image_util_encode_create() +* @see image_util_encode_set_resolution() +* @see image_util_encode_set_input_buffer() +* @see image_util_encode_set_output_path() +* @see image_util_encode_set_output_buffer() +* @see image_util_encode_destroy() +*/ +int image_util_encode_run(image_util_encode_h handle, unsigned long long *size); + +/** +* @brief Starts encoding of the image and fills the output buffer, set using image_util_encode_set_output_buffer() or image_util_encode_set_output_path(). +* @since_tizen 3.0 +* +* @remarks The output will be stored in the pointer set to image_util_encode_set_output_buffer() or image_util_encode_set_output_path().\n +* The function executes asynchronously, which contains complete callback. +* +* @param[in] handle The handle to image util encoding +* @param[in] callback The callback function to be invoked +* @param[in] user_data The user data to be passed to the callback function +* +* @return @c 0 on success, +* otherwise a negative error value +* +* @retval #IMAGE_UTIL_ERROR_NONE Successful +* @retval #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #IMAGE_UTIL_ERROR_INVALID_OPERATION Invalid operation +* +* @pre image_util_encode_create() +* @pre image_util_encode_set_resolution() +* @pre image_util_encode_set_input_buffer() +* @pre image_util_encode_set_output_buffer()/image_util_encode_set_output_path() +* +* @post image_util_encode_destroy() +* +* @see image_util_encode_create() +* @see image_util_encode_set_resolution() +* @see image_util_encode_set_input_buffer() +* @see image_util_encode_set_output_path() +* @see image_util_encode_set_output_buffer() +* @see image_util_encode_destroy() +*/ +int image_util_encode_run_async(image_util_encode_h handle, image_util_encode_completed_cb callback, void *user_data); + +/** +* @brief Destroys the image encoding handle. +* @since_tizen 3.0 +* +* @remarks Any image handle created should be destroyed. +* +* @param[in] handle The handle to image util encoding +* +* @return @c 0 on success, +* otherwise a negative error value +* +* @retval #IMAGE_UTIL_ERROR_NONE Successful +* @retval #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* @retval #IMAGE_UTIL_ERROR_INVALID_OPERATION Invalid operation +* +* @pre image_util_encode_create() +* +* @see image_util_encode_create() +*/ +int image_util_encode_destroy(image_util_encode_h handle); /** * @} diff --git a/include/image_util_private.h b/include/image_util_private.h index 0722826..15be490 100755 --- a/include/image_util_private.h +++ b/include/image_util_private.h @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" @@ -84,6 +85,37 @@ typedef struct { bool set_crop; } transformation_s; +typedef struct { + void *user_data; + image_util_decode_completed_cb image_decode_completed_cb; +} decode_cb_s; + +typedef struct { + void *user_data; + image_util_encode_completed_cb image_encode_completed_cb; +} encode_cb_s; + +typedef struct { + image_util_type_e image_type; + void *src_buffer; + unsigned long long src_size; + void **dst_buffer; + unsigned long long dst_size; + const char *path; + MMHandleType image_h; + unsigned long width; + unsigned long height; + bool is_decode; + decode_cb_s *_decode_cb; + encode_cb_s *_encode_cb; + + /* for multi instance */ + GCond thread_cond; + GMutex thread_mutex; + GThread *thread; + + bool is_finish; +} decode_encode_s; /** * @} diff --git a/include/image_util_type.h b/include/image_util_type.h index 1d81fba..5d851ce 100755 --- a/include/image_util_type.h +++ b/include/image_util_type.h @@ -124,6 +124,84 @@ typedef struct transformation_s *transformation_h; */ typedef void(*image_util_transform_completed_cb)(media_packet_h *dst, int error_code, void *user_data); +/** + * @brief Enumeration for Image types. + * @since_tizen 3.0 + */ +typedef enum { + IMAGE_UTIL_PNG, /**< Image format PNG */ + IMAGE_UTIL_GIF, /**< Image format GIF */ +} image_util_type_e; + +/** + * @brief Enumeration for PNG compression values. + * @since_tizen 3.0 + */ +typedef enum { + IMAGE_UTIL_PNG_COMPRESSION_0 = 0, /**< No compression */ + IMAGE_UTIL_PNG_COMPRESSION_1 = 1, /**< Compression Level 1. Best speed */ + IMAGE_UTIL_PNG_COMPRESSION_2 = 2, /**< Compression Level 2 */ + IMAGE_UTIL_PNG_COMPRESSION_3 = 3, /**< Compression Level 3 */ + IMAGE_UTIL_PNG_COMPRESSION_4 = 4, /**< Compression Level 4 */ + IMAGE_UTIL_PNG_COMPRESSION_5 = 5, /**< Compression Level 5 */ + IMAGE_UTIL_PNG_COMPRESSION_6 = 6, /**< Compression Level 6 */ + IMAGE_UTIL_PNG_COMPRESSION_7 = 7, /**< Compression Level 7 */ + IMAGE_UTIL_PNG_COMPRESSION_8 = 8, /**< Compression Level 8 */ + IMAGE_UTIL_PNG_COMPRESSION_9 = 9 /**< Compression Level 9. Best compression */ +} image_util_png_compression_e; + +/** +* @ingroup CAPI_MEDIA_IMAGE_UTIL_MODULE +* @brief Called when Image-util decoding is finished just before returning the output. +* @since_tizen 3.0 +* +* @remarks The output will be stored in the pointer set using image_util_decode_set_output_buffer() after this callback. +* +* @param[in] error_code The error code of image util decoding +* #IMAGE_UTIL_ERROR_NONE Successful +* #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* #IMAGE_UTIL_ERROR_INVALID_OPERATION Invalid operation +* @param[in] user_data The user data passed from the callback registration function +* @param[in] width Width of the decoded image +* @param[in] height Height of the decoded image +* @param[in] size Size of the decoded image +* +* @pre image_util_decode_run() will invoke this function. +*/ +typedef void (*image_util_decode_completed_cb) (int error_code, void *user_data, unsigned long width, unsigned long height, unsigned long long size); + +/** +* @ingroup CAPI_MEDIA_IMAGE_UTIL_MODULE +* @brief Called when Image-util encoding is finished just before returning the output. +* @since_tizen 3.0 +* +* @remarks The output will be stored in the pointer set using image_util_encode_set_output_buffer() or image_util_encode_set_output_path() after this callback. +* +* @param[in] error_code The error code of image util encoding +* #IMAGE_UTIL_ERROR_NONE Successful +* #IMAGE_UTIL_ERROR_INVALID_PARAMETER Invalid parameter +* #IMAGE_UTIL_ERROR_INVALID_OPERATION Invalid operation +* @param[in] user_data The user data passed from the callback registration function +* @param[in] size Size of the encoded image +* +* @pre image_util_encode_run() will invoke this function. +*/ +typedef void (*image_util_encode_completed_cb) (int error_code, void *user_data, unsigned long long size); + +/** +* @ingroup CAPI_MEDIA_IMAGE_UTIL_MODULE +* @brief Image-util decoding handle. +* @since_tizen 3.0 +*/ +typedef void *image_util_decode_h; + +/** +* @ingroup CAPI_MEDIA_IMAGE_UTIL_MODULE +* @brief Image-util encoding handle. +* @since_tizen 3.0 +*/ +typedef void *image_util_encode_h; + /** * @} */ diff --git a/packaging/capi-media-image-util.spec b/packaging/capi-media-image-util.spec index 78a98c9..10c6d3f 100755 --- a/packaging/capi-media-image-util.spec +++ b/packaging/capi-media-image-util.spec @@ -10,9 +10,13 @@ BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(mmutil-jpeg) BuildRequires: pkgconfig(mmutil-imgp) BuildRequires: pkgconfig(mmutil-imgcv) +BuildRequires: pkgconfig(mmutil-png) +BuildRequires: pkgconfig(mmutil-gif) BuildRequires: pkgconfig(capi-base-common) BuildRequires: pkgconfig(capi-media-tool) BuildRequires: cmake +BuildRequires: libpng-devel +BuildRequires: giflib-devel %description A Image Utility library in Tizen Native API package @@ -26,11 +30,21 @@ Requires: pkgconfig(mm-common) Requires: pkgconfig(mmutil-jpeg) Requires: pkgconfig(mmutil-imgp) Requires: pkgconfig(mmutil-imgcv) +Requires: pkgconfig(mmutil-png) +Requires: pkgconfig(mmutil-gif) Requires: pkgconfig(capi-base-common) %description devel A Image Utility library in Tizen Native API (Development) package +%package tool +Summary: Image Utility tools +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description tool +Image Utility Library - Tools. + %prep %setup -q cp %{SOURCE1001} . @@ -69,3 +83,8 @@ cp LICENSE.APLv2.0 %{buildroot}/usr/share/license/%{name} %{_libdir}/lib*.so %{_libdir}/pkgconfig/*.pc %{_includedir}/media/*.h + +%files tool +%manifest %{name}.manifest +%defattr(-,root,root,-) +%{_bindir}/* diff --git a/src/image_util.c b/src/image_util.c index 74ddf4d..5864b40 100755 --- a/src/image_util.c +++ b/src/image_util.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include #include @@ -751,3 +753,841 @@ int image_util_extract_color_from_memory(const unsigned char *image_buffer, int return _convert_image_util_error_code(__func__, ret); } + +static int _image_util_decode_create_png_handle(decode_encode_s * handle) +{ + int err = MM_UTIL_ERROR_NONE; + + image_util_retvm_if((handle == NULL), MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid Handle"); + + mm_util_png_data *_handle = (mm_util_png_data *) calloc(1, sizeof(mm_util_png_data)); + image_util_retvm_if((_handle == NULL), MM_UTIL_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY(0x%08x)", MM_UTIL_ERROR_OUT_OF_MEMORY); + + mm_util_init_decode_png(_handle); + + handle->image_h = (MMHandleType) _handle; + + return err; +} + +static int _image_util_decode_create_gif_handle(decode_encode_s * handle) +{ + int err = MM_UTIL_ERROR_NONE; + + image_util_retvm_if((handle == NULL), MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid Handle"); + + mm_util_gif_data *_handle = (mm_util_gif_data *) calloc(1, sizeof(mm_util_gif_data)); + image_util_retvm_if((_handle == NULL), MM_UTIL_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY(0x%08x)", MM_UTIL_ERROR_OUT_OF_MEMORY); + + handle->image_h = (MMHandleType) _handle; + + return err; +} + +int image_util_decode_create(image_util_type_e image_type, image_util_decode_h * handle) +{ + int err = MM_UTIL_ERROR_NONE; + + image_util_debug("image_util_decode_create"); + + image_util_retvm_if((handle == NULL), IMAGE_UTIL_ERROR_INVALID_PARAMETER, "Invalid Handle"); + + decode_encode_s *_handle = (decode_encode_s *) calloc(1, sizeof(decode_encode_s)); + image_util_retvm_if((_handle == NULL), IMAGE_UTIL_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY(0x%08x)", IMAGE_UTIL_ERROR_OUT_OF_MEMORY); + + _handle->image_type = image_type; + _handle->src_buffer = NULL; + _handle->dst_buffer = NULL; + _handle->path = NULL; + _handle->image_h = 0; + _handle->is_decode = TRUE; + + switch (image_type) { + case IMAGE_UTIL_PNG: + err = _image_util_decode_create_png_handle(_handle); + break; + case IMAGE_UTIL_GIF: + err = _image_util_decode_create_gif_handle(_handle); + break; + default: + err = MM_UTIL_ERROR_INVALID_PARAMETER; + break; + } + + if (err != MM_UTIL_ERROR_NONE) { + image_util_error("Error - create image handle"); + IMAGE_UTIL_SAFE_FREE(_handle); + return _convert_image_util_error_code(__func__, err); + } + + *handle = (image_util_decode_h) _handle; + + return _convert_image_util_error_code(__func__, err); +} + +int image_util_decode_set_input_path(image_util_decode_h handle, const char *path) +{ + int err = IMAGE_UTIL_ERROR_NONE; + decode_encode_s *_handle = (decode_encode_s *) handle; + + if (_handle == NULL || _handle->is_decode == FALSE) { + image_util_error("Invalid Handle"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + image_util_retvm_if((path == NULL || strlen(path) == 0), IMAGE_UTIL_ERROR_NO_SUCH_FILE, "Invalid path"); + + if (_handle->src_buffer) + _handle->src_buffer = NULL; + + _handle->path = path; + + return err; +} + +int image_util_decode_set_input_buffer(image_util_decode_h handle, const unsigned char *src_buffer, unsigned long long src_size) +{ + int err = IMAGE_UTIL_ERROR_NONE; + decode_encode_s *_handle = (decode_encode_s *) handle; + + if (_handle == NULL || _handle->is_decode == FALSE) { + image_util_error("Invalid Handle"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + if (src_buffer == NULL || src_size == 0) { + image_util_error("Invalid input buffer"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + + if (_handle->path) + _handle->path = NULL; + + _handle->src_buffer = (void *)src_buffer; + _handle->src_size = src_size; + + return err; +} + +int image_util_decode_set_output_buffer(image_util_decode_h handle, unsigned char **dst_buffer) +{ + int err = IMAGE_UTIL_ERROR_NONE; + decode_encode_s *_handle = (decode_encode_s *) handle; + + if (_handle == NULL || _handle->is_decode == FALSE) { + image_util_error("Invalid Handle"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + if (dst_buffer == NULL) { + image_util_error("Invalid output buffer"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + + _handle->dst_buffer = (void **)dst_buffer; + + return err; +} + +static int _image_util_decode_internal(decode_encode_s * _handle) +{ + int err = MM_UTIL_ERROR_NONE; + + switch (_handle->image_type) { + case IMAGE_UTIL_PNG: + { + mm_util_png_data *png_data; + + png_data = (mm_util_png_data *) _handle->image_h; + if (png_data == NULL) { + image_util_error("Invalid png data"); + return MM_UTIL_ERROR_INVALID_PARAMETER; + } + + if (_handle->path) + err = mm_util_decode_from_png_file(png_data, _handle->path); + else + err = mm_util_decode_from_png_memory(png_data, &_handle->src_buffer, _handle->src_size); + + if (err == MM_UTIL_ERROR_NONE) { + *(_handle->dst_buffer) = png_data->data; + _handle->dst_size = png_data->size; + _handle->width = png_data->width; + _handle->height = png_data->height; + } + } + break; + case IMAGE_UTIL_GIF: + { + mm_util_gif_data *gif_data; + + gif_data = (mm_util_gif_data *) _handle->image_h; + if (gif_data == NULL) { + image_util_error("Invalid gif data"); + return MM_UTIL_ERROR_INVALID_PARAMETER; + } + + if (_handle->path) + err = mm_util_decode_from_gif_file(gif_data, _handle->path); + else + err = mm_util_decode_from_gif_memory(gif_data, &_handle->src_buffer); + + if (err == MM_UTIL_ERROR_NONE) { + *(_handle->dst_buffer) = gif_data->frames[0].data; + _handle->dst_size = gif_data->size; + _handle->width = gif_data->width; + _handle->height = gif_data->height; + } + } + break; + default: + err = MM_UTIL_ERROR_INVALID_PARAMETER; + break; + } + + return err; +} + +int image_util_decode_run(image_util_decode_h handle, unsigned long *width, unsigned long *height, unsigned long long *size) +{ + int err = MM_UTIL_ERROR_NONE; + decode_encode_s *_handle = (decode_encode_s *) handle; + + if (_handle == NULL || _handle->is_decode == FALSE) { + image_util_error("Invalid Handle"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + if ((_handle->path == NULL && _handle->src_buffer == NULL) || _handle->dst_buffer == NULL) { + image_util_error("Invalid input/output"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + + err = _image_util_decode_internal(_handle); + + if (err != MM_UTIL_ERROR_NONE) { + image_util_error("Error - decode run"); + return _convert_image_util_error_code(__func__, err); + } + + if (width) + *width = _handle->width; + if (height) + *height = _handle->height; + if (size) + *size = _handle->dst_size; + + return _convert_image_util_error_code(__func__, err); +} + +gpointer _image_util_decode_thread(gpointer data) +{ + decode_encode_s *_handle = (decode_encode_s *) data; + int err = MM_UTIL_ERROR_NONE; + gint64 end_time = 0; + + if (!_handle) { + image_util_error("[ERROR] - handle"); + return NULL; + } + + while (!_handle->is_finish) { + end_time = g_get_monotonic_time() + 1 * G_TIME_SPAN_SECOND; + image_util_debug("waiting..."); + g_mutex_lock(&(_handle->thread_mutex)); + g_cond_wait_until(&(_handle->thread_cond), &(_handle->thread_mutex), end_time); + image_util_debug("<=== get run decode thread signal"); + g_mutex_unlock(&(_handle->thread_mutex)); + + if (_handle->is_finish) { + image_util_debug("exit loop"); + break; + } + + err = _image_util_decode_internal(_handle); + if(err == MM_UTIL_ERROR_NONE) { + image_util_debug("Success - decode_internal"); + } else{ + image_util_error("Error - decode_internal"); + } + if (_handle->_decode_cb) { + image_util_debug("completed_cb"); + _handle->is_finish = TRUE; + _handle->_decode_cb->image_decode_completed_cb(_convert_image_util_error_code(__func__, err), _handle->_decode_cb->user_data, _handle->width, _handle->height, _handle->dst_size); + } + } + + image_util_debug("exit thread"); + + return NULL; +} + +static int _image_util_decode_create_thread(decode_encode_s * handle) +{ + int err = MM_UTIL_ERROR_NONE; + + image_util_retvm_if((handle == NULL), MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid Handle"); + + g_mutex_init(&(handle->thread_mutex)); + + g_cond_init(&(handle->thread_cond)); + + /*create threads */ + handle->thread = g_thread_new("decode_thread", (GThreadFunc) _image_util_decode_thread, (gpointer) handle); + if (!handle->thread) { + image_util_error("ERROR - create thread"); + g_mutex_clear(&(handle->thread_mutex)); + + g_cond_clear(&(handle->thread_cond)); + return MM_UTIL_ERROR_INVALID_OPERATION; + } + + return err; +} + +int image_util_decode_run_async(image_util_decode_h handle, image_util_decode_completed_cb completed_cb, void *user_data) +{ + int err = MM_UTIL_ERROR_NONE; + decode_encode_s *_handle = (decode_encode_s *) handle; + + if (_handle == NULL || _handle->is_decode == FALSE) { + image_util_error("Invalid Handle"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + if ((_handle->path == NULL && _handle->src_buffer == NULL) || _handle->dst_buffer == NULL) { + image_util_error("Invalid input/output"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + image_util_retvm_if((completed_cb == NULL), IMAGE_UTIL_ERROR_INVALID_PARAMETER, "Invalid callback"); + + if (_handle->_decode_cb != NULL) { + IMAGE_UTIL_SAFE_FREE(_handle->_decode_cb); + _handle->_decode_cb = NULL; + } + _handle->_decode_cb = (decode_cb_s *) calloc(1, sizeof(decode_cb_s)); + image_util_retvm_if((_handle->_decode_cb == NULL), IMAGE_UTIL_ERROR_OUT_OF_MEMORY, "Out of memory"); + + _handle->_decode_cb->user_data = user_data; + _handle->_decode_cb->image_decode_completed_cb = completed_cb; + + err = _image_util_decode_create_thread(_handle); + + return _convert_image_util_error_code(__func__, err); +} + +int image_util_decode_destroy(image_util_decode_h handle) +{ + int err = IMAGE_UTIL_ERROR_NONE; + decode_encode_s *_handle = (decode_encode_s *) handle; + + image_util_debug("image_util_encode_png_destroy"); + + if (_handle == NULL || _handle->is_decode == FALSE) { + image_util_error("Invalid Handle"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + + switch (_handle->image_type) { + case IMAGE_UTIL_PNG: + { + mm_util_png_data *png_data; + + png_data = (mm_util_png_data *) _handle->image_h; + if (png_data == NULL) { + image_util_error("Invalid png data"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + IMAGE_UTIL_SAFE_FREE(png_data); + } + break; + case IMAGE_UTIL_GIF: + { + mm_util_gif_data *gif_data; + + gif_data = (mm_util_gif_data *) _handle->image_h; + if (gif_data == NULL) { + image_util_error("Invalid gif data"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + IMAGE_UTIL_SAFE_FREE(gif_data); + } + break; + default: + err = IMAGE_UTIL_ERROR_INVALID_PARAMETER; + break; + } + + /* g_thread_exit(handle->thread); */ + if (_handle->thread) { + _handle->is_finish = TRUE; + g_mutex_lock(&(_handle->thread_mutex)); + g_cond_signal(&(_handle->thread_cond)); + image_util_debug("===> send signal(finish) to decode_thread"); + g_mutex_unlock(&(_handle->thread_mutex)); + + g_thread_join(_handle->thread); + + g_mutex_clear(&(_handle->thread_mutex)); + + g_cond_clear(&(_handle->thread_cond)); + } + + IMAGE_UTIL_SAFE_FREE(_handle); + + return err; +} + +static int _image_util_encode_create_png_handle(decode_encode_s * handle) +{ + int err = MM_UTIL_ERROR_NONE; + + image_util_retvm_if((handle == NULL), MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid Handle"); + + mm_util_png_data *_handle = (mm_util_png_data *) calloc(1, sizeof(mm_util_png_data)); + image_util_retvm_if((_handle == NULL), MM_UTIL_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY(0x%08x)", MM_UTIL_ERROR_OUT_OF_MEMORY); + + mm_util_init_encode_png(_handle); + + handle->image_h = (MMHandleType) _handle; + + return err; +} + +static int _image_util_encode_create_gif_handle(decode_encode_s * handle) +{ + int err = MM_UTIL_ERROR_NONE; + + image_util_retvm_if((handle == NULL), MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid Handle"); + + mm_util_gif_data *_handle = (mm_util_gif_data *) calloc(1, sizeof(mm_util_gif_data)); + image_util_retvm_if((_handle == NULL), MM_UTIL_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY(0x%08x)", MM_UTIL_ERROR_OUT_OF_MEMORY); + + _handle->frames = (mm_util_gif_frame_data *) calloc(1, sizeof(mm_util_gif_frame_data)); + image_util_retvm_if((_handle->frames == NULL), MM_UTIL_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY(0x%08x)", MM_UTIL_ERROR_OUT_OF_MEMORY); + + mm_util_gif_encode_set_image_count(_handle, 1); + handle->image_h = (MMHandleType) _handle; + + return err; +} + +int image_util_encode_create(image_util_type_e image_type, image_util_encode_h * handle) +{ + int err = MM_UTIL_ERROR_NONE; + + image_util_debug("image_util_encode_create"); + + image_util_retvm_if((handle == NULL), IMAGE_UTIL_ERROR_INVALID_PARAMETER, "Invalid Handle"); + + decode_encode_s *_handle = (decode_encode_s *) calloc(1, sizeof(decode_encode_s)); + image_util_retvm_if((_handle == NULL), IMAGE_UTIL_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY(0x%08x)", IMAGE_UTIL_ERROR_OUT_OF_MEMORY); + + _handle->image_type = image_type; + _handle->src_buffer = NULL; + _handle->dst_buffer = NULL; + _handle->path = NULL; + _handle->image_h = 0; + _handle->is_decode = FALSE; + + switch (image_type) { + case IMAGE_UTIL_PNG: + err = _image_util_encode_create_png_handle(_handle); + break; + case IMAGE_UTIL_GIF: + err = _image_util_encode_create_gif_handle(_handle); + break; + default: + err = MM_UTIL_ERROR_INVALID_PARAMETER; + break; + } + + if (err != MM_UTIL_ERROR_NONE) { + image_util_error("Error - create image handle"); + IMAGE_UTIL_SAFE_FREE(_handle); + return _convert_image_util_error_code(__func__, err); + } + + *handle = (image_util_encode_h) _handle; + + return _convert_image_util_error_code(__func__, err); +} + +int image_util_encode_set_resolution(image_util_encode_h handle, unsigned long width, unsigned long height) +{ + int err = IMAGE_UTIL_ERROR_NONE; + decode_encode_s *_handle = (decode_encode_s *) handle; + + if (_handle == NULL || _handle->is_decode == TRUE) { + image_util_error("Invalid Handle"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + image_util_retvm_if((_image_util_check_resolution(width, height) == false), IMAGE_UTIL_ERROR_INVALID_PARAMETER, "Invalid resolution"); + + switch (_handle->image_type) { + case IMAGE_UTIL_PNG: + { + mm_util_png_data *png_data; + + png_data = (mm_util_png_data *) _handle->image_h; + if (png_data == NULL) { + image_util_error("Invalid png data"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + mm_util_png_encode_set_width(png_data, width); + mm_util_png_encode_set_height(png_data, height); + } + break; + case IMAGE_UTIL_GIF: + { + mm_util_gif_data *gif_data; + + gif_data = (mm_util_gif_data *) _handle->image_h; + if (gif_data == NULL) { + image_util_error("Invalid gif data"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + mm_util_gif_encode_set_width(gif_data, width); + mm_util_gif_encode_set_height(gif_data, height); + } + break; + default: + err = IMAGE_UTIL_ERROR_INVALID_PARAMETER; + break; + } + + _handle->width = width; + _handle->height = height; + + return err; +} + +int image_util_encode_set_png_compression(image_util_encode_h handle, image_util_png_compression_e compression) +{ + int err = IMAGE_UTIL_ERROR_NONE; + decode_encode_s *_handle = (decode_encode_s *) handle; + mm_util_png_data *png_data; + + if (_handle == NULL || _handle->is_decode == TRUE) { + image_util_error("Invalid Handle"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + if (_handle->image_type != IMAGE_UTIL_PNG) { + image_util_error("Wrong image format"); + return IMAGE_UTIL_ERROR_NOT_SUPPORTED_FORMAT; + } + png_data = (mm_util_png_data *) _handle->image_h; + if (png_data == NULL) { + image_util_error("Invalid png data"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + + mm_util_png_encode_set_compression_level(png_data, compression); + + return err; +} + +int image_util_encode_set_input_buffer(image_util_encode_h handle, const unsigned char *src_buffer) +{ + int err = IMAGE_UTIL_ERROR_NONE; + decode_encode_s *_handle = (decode_encode_s *) handle; + + if (_handle == NULL || _handle->is_decode == TRUE) { + image_util_error("Invalid Handle"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + if (src_buffer == NULL) { + image_util_error("Invalid input buffer"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + + _handle->src_buffer = (void *)src_buffer; + + return err; +} + +int image_util_encode_set_output_path(image_util_encode_h handle, const char *path) +{ + int err = IMAGE_UTIL_ERROR_NONE; + decode_encode_s *_handle = (decode_encode_s *) handle; + + if (_handle == NULL || _handle->is_decode == TRUE) { + image_util_error("Invalid Handle"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + image_util_retvm_if((path == NULL || strlen(path) == 0), IMAGE_UTIL_ERROR_NO_SUCH_FILE, "Invalid path"); + + if (_handle->dst_buffer) + _handle->dst_buffer = NULL; + + _handle->path = path; + + return err; +} + +int image_util_encode_set_output_buffer(image_util_encode_h handle, unsigned char **dst_buffer) +{ + int err = IMAGE_UTIL_ERROR_NONE; + decode_encode_s *_handle = (decode_encode_s *) handle; + + if (_handle == NULL || _handle->is_decode == TRUE) { + image_util_error("Invalid Handle"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + if (dst_buffer == NULL) { + image_util_error("Invalid output buffer"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + + if (_handle->path) + _handle->path = NULL; + + _handle->dst_buffer = (void **)dst_buffer; + + return err; +} + +static int _image_util_encode_internal(decode_encode_s * _handle) +{ + int err = MM_UTIL_ERROR_NONE; + + switch (_handle->image_type) { + case IMAGE_UTIL_PNG: + { + mm_util_png_data *png_data; + + png_data = (mm_util_png_data *) _handle->image_h; + if (png_data == NULL) { + image_util_error("Invalid png data"); + return MM_UTIL_ERROR_INVALID_PARAMETER; + } + + if (_handle->path) + err = mm_util_encode_to_png_file(&(_handle->src_buffer), png_data, _handle->path); + else + err = mm_util_encode_to_png_memory(&(_handle->src_buffer), png_data); + + if (err == MM_UTIL_ERROR_NONE) { + if (_handle->dst_buffer) + *(_handle->dst_buffer) = png_data->data; + _handle->dst_size = png_data->size; + _handle->width = png_data->width; + _handle->height = png_data->height; + } + } + break; + case IMAGE_UTIL_GIF: + { + mm_util_gif_data *gif_data; + void *dst_buffer = NULL; + + gif_data = (mm_util_gif_data *) _handle->image_h; + if (gif_data == NULL) { + image_util_error("Invalid png data"); + return MM_UTIL_ERROR_INVALID_PARAMETER; + } + + gif_data->frames[0].data = _handle->src_buffer; + if (_handle->path) + err = mm_util_encode_gif_to_file(gif_data, _handle->path); + else + err = mm_util_encode_gif_to_memory(gif_data, &dst_buffer); + + if (err == MM_UTIL_ERROR_NONE) { + if (_handle->dst_buffer) + *(_handle->dst_buffer) = (unsigned char *)dst_buffer; + _handle->dst_size = gif_data->size; + _handle->width = gif_data->width; + _handle->height = gif_data->height; + } + } + break; + default: + err = MM_UTIL_ERROR_INVALID_PARAMETER; + break; + } + + return err; +} + +int image_util_encode_run(image_util_encode_h handle, unsigned long long *size) +{ + int err = MM_UTIL_ERROR_NONE; + decode_encode_s *_handle = (decode_encode_s *) handle; + + if (_handle == NULL || _handle->is_decode == TRUE) { + image_util_error("Invalid Handle"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + if ((_handle->path == NULL && _handle->dst_buffer == NULL) || _handle->src_buffer == NULL) { + image_util_error("Invalid input/output"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + image_util_retvm_if((_image_util_check_resolution(_handle->width, _handle->height) == false), IMAGE_UTIL_ERROR_INVALID_PARAMETER, "Invalid resolution"); + + err = _image_util_encode_internal(_handle); + + if (err != MM_UTIL_ERROR_NONE) { + image_util_error("Error - encode run"); + return _convert_image_util_error_code(__func__, err); + } + + if(size) + *size = _handle->dst_size; + + return _convert_image_util_error_code(__func__, err); +} + +gpointer _image_util_encode_thread(gpointer data) +{ + decode_encode_s *_handle = (decode_encode_s *) data; + int err = MM_UTIL_ERROR_NONE; + gint64 end_time = 0; + + if (!_handle) { + image_util_error("[ERROR] - handle"); + return NULL; + } + + while (!_handle->is_finish) { + end_time = g_get_monotonic_time() + 1 * G_TIME_SPAN_SECOND; + image_util_debug("waiting..."); + g_mutex_lock(&(_handle->thread_mutex)); + g_cond_wait_until(&(_handle->thread_cond), &(_handle->thread_mutex), end_time); + image_util_debug("<=== get run encode thread signal"); + g_mutex_unlock(&(_handle->thread_mutex)); + + if (_handle->is_finish) { + image_util_debug("exit loop"); + break; + } + + err = _image_util_encode_internal(_handle); + if(err == MM_UTIL_ERROR_NONE) { + image_util_debug("Success - encode_internal"); + } else{ + image_util_error("Error - encode_internal"); + } + if (_handle->_encode_cb) { + image_util_debug("completed_cb"); + _handle->is_finish = TRUE; + _handle->_encode_cb->image_encode_completed_cb(_convert_image_util_error_code(__func__, err), _handle->_encode_cb->user_data, _handle->dst_size); + } + } + + image_util_debug("exit thread"); + + return NULL; +} + +static int _image_util_encode_create_thread(decode_encode_s * handle) +{ + int ret = MM_UTIL_ERROR_NONE; + + image_util_retvm_if((handle == NULL), MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid Handle"); + + g_mutex_init(&(handle->thread_mutex)); + + g_cond_init(&(handle->thread_cond)); + + /*create threads */ + handle->thread = g_thread_new("encode_thread", (GThreadFunc) _image_util_encode_thread, (gpointer) handle); + if (!handle->thread) { + image_util_error("ERROR - create thread"); + g_mutex_clear(&(handle->thread_mutex)); + + g_cond_clear(&(handle->thread_cond)); + return MM_UTIL_ERROR_INVALID_OPERATION; + } + + return ret; +} + +int image_util_encode_run_async(image_util_encode_h handle, image_util_encode_completed_cb completed_cb, void *user_data) +{ + int err = MM_UTIL_ERROR_NONE; + decode_encode_s *_handle = (decode_encode_s *) handle; + + if (_handle == NULL || _handle->is_decode == TRUE) { + image_util_error("Invalid Handle"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + if ((_handle->path == NULL && _handle->dst_buffer == NULL) || _handle->src_buffer == NULL) { + image_util_error("Invalid input/output"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + image_util_retvm_if((_image_util_check_resolution(_handle->width, _handle->height) == false), IMAGE_UTIL_ERROR_INVALID_PARAMETER, "Invalid resolution"); + + image_util_retvm_if((completed_cb == NULL), IMAGE_UTIL_ERROR_INVALID_PARAMETER, "Invalid callback"); + + if (_handle->_encode_cb != NULL) { + IMAGE_UTIL_SAFE_FREE(_handle->_encode_cb); + _handle->_encode_cb = NULL; + } + _handle->_encode_cb = (encode_cb_s *) calloc(1, sizeof(encode_cb_s)); + image_util_retvm_if((_handle->_encode_cb == NULL), IMAGE_UTIL_ERROR_OUT_OF_MEMORY, "Out of memory"); + + _handle->_encode_cb->user_data = user_data; + _handle->_encode_cb->image_encode_completed_cb = completed_cb; + + err = _image_util_encode_create_thread(_handle); + + return _convert_image_util_error_code(__func__, err); +} + +int image_util_encode_destroy(image_util_encode_h handle) +{ + int err = IMAGE_UTIL_ERROR_NONE; + decode_encode_s *_handle = (decode_encode_s *) handle; + + image_util_debug("image_util_encode_destroy"); + + if (_handle == NULL || _handle->is_decode == TRUE) { + image_util_error("Invalid Handle"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + + switch (_handle->image_type) { + case IMAGE_UTIL_PNG: + { + mm_util_png_data *png_data; + + png_data = (mm_util_png_data *) _handle->image_h; + if (png_data == NULL) { + image_util_error("Invalid png data"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + IMAGE_UTIL_SAFE_FREE(png_data); + } + break; + case IMAGE_UTIL_GIF: + { + mm_util_gif_data *gif_data; + + gif_data = (mm_util_gif_data *) _handle->image_h; + if (gif_data == NULL) { + image_util_error("Invalid gif data"); + return IMAGE_UTIL_ERROR_INVALID_PARAMETER; + } + IMAGE_UTIL_SAFE_FREE(gif_data); + } + break; + default: + err = IMAGE_UTIL_ERROR_INVALID_PARAMETER; + break; + } + + /* g_thread_exit(handle->thread); */ + if (_handle->thread) { + _handle->is_finish = TRUE; + g_mutex_lock(&(_handle->thread_mutex)); + g_cond_signal(&(_handle->thread_cond)); + image_util_debug("===> send signal(finish) to decode_thread"); + g_mutex_unlock(&(_handle->thread_mutex)); + + g_thread_join(_handle->thread); + + g_mutex_clear(&(_handle->thread_mutex)); + + g_cond_clear(&(_handle->thread_cond)); + } + + IMAGE_UTIL_SAFE_FREE(_handle); + + return err; +}