#include "media-thumbnail.h"
#include "media-thumbnail-debug.h"
#include <aul.h>
+#if defined(USE_MEMORY_USAGE_REDUCTION)
+#include <mm_util_gif.h>
+#include <mm_util_jpeg.h>
+#include <libexif/exif-data.h>
+#endif
+
#define MAX_THUMB_SIZE 2000
#define MIME_TYPE_TIFF "image/tiff"
return err;
}
-static int __adjust_thumb_ratio(const char *path, unsigned int *width, unsigned int *height)
+static int __adjust_thumb_ratio(const char *path, unsigned int *width, unsigned int *height,
+ unsigned int *image_w, unsigned int *image_h, mm_util_img_codec_type *image_type)
{
int err = MS_MEDIA_ERR_NONE;
- unsigned int image_w = 0;
- unsigned int image_h = 0;
- mm_util_img_codec_type image_type = 0;
-
- err = mm_util_extract_image_info(path, &image_type, &image_w, &image_h);
+#if defined(ENABLE_IMAGE_SIZE_LIMITATION)
+ const size_t image_size_limit[IMG_CODEC_UNKNOWN_TYPE] = {
+ [IMG_CODEC_JPEG] = (4096 * 4096),
+ [IMG_CODEC_PNG] = (3000 * 3000),
+ [IMG_CODEC_GIF] = (3000 * 3000),
+ };
+#endif
+
+ err = mm_util_extract_image_info(path, image_type, image_w, image_h);
thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_extract_image_info: %d", err);
- thumb_retvm_if(image_type == IMG_CODEC_UNKNOWN_TYPE, MS_MEDIA_ERR_THUMB_UNSUPPORTED, "Unsupported image codec");
+ thumb_retvm_if(*image_type == IMG_CODEC_UNKNOWN_TYPE, MS_MEDIA_ERR_THUMB_UNSUPPORTED, "Unsupported image codec");
+
+#if defined(ENABLE_IMAGE_SIZE_LIMITATION)
+ if ((*image_type == IMG_CODEC_JPEG) ||
+ (*image_type == IMG_CODEC_PNG) ||
+ (*image_type == IMG_CODEC_GIF))
+ if ((size_t)((*image_w) * (*image_h)) > image_size_limit[*image_type]) {
+ thumb_err("Unsupported image size [%u x %u] limit [%zu]", *image_w, *image_h, image_size_limit[*image_type]);
+ return MS_MEDIA_ERR_UNSUPPORTED_CONTENT;
+ }
+#endif
+ __media_thumb_get_proper_thumb_size(*image_w, *image_h, width, height);
+
+ return MS_MEDIA_ERR_NONE;
+}
+
+#if defined(USE_MEMORY_USAGE_REDUCTION)
+static mm_util_rotate_type_e __get_image_orientation(const char *path)
+{
+ ExifData *ed = NULL;
+ ExifEntry *entry = NULL;
+ short orientation = 0;
+ mm_util_rotate_type_e rotation = MM_UTIL_ROTATE_0;
+
+ ed = exif_data_new_from_file(path);
+ thumb_retvm_if(!ed, MM_UTIL_ROTATE_0, "no exif data");
+
+ entry = exif_data_get_entry(ed, EXIF_TAG_ORIENTATION);
+ if (!entry) {
+ thumb_info("no orientation entry");
+ exif_data_unref(ed);
+ return MM_UTIL_ROTATE_0;
+ }
- __media_thumb_get_proper_thumb_size(image_w, image_h, width, height);
+ orientation = exif_get_short(entry->data, exif_data_get_byte_order(ed));
+
+ /* exif orientation
+ * 0 - not available, 1- normal, 2 - hflip, 3 - rot_180,
+ * 4 - vflip, 5 - tranpose, 6 - rot_90, 7 - transverse, 8 - rot_270
+ */
+ switch (orientation) {
+ case 3:
+ rotation = MM_UTIL_ROTATE_180;
+ break;
+ case 6:
+ rotation = MM_UTIL_ROTATE_90;
+ break;
+ case 8:
+ rotation = MM_UTIL_ROTATE_270;
+ break;
+ default:
+ thumb_warn("not supported orientation[%d], rotation will be 0", orientation);
+ rotation = MM_UTIL_ROTATE_0;
+ break;
+ };
+
+ exif_data_unref(ed);
+ thumb_info("orientation: %d, rotation: %d", orientation, rotation);
+
+ return rotation;
+}
+
+static int __create_gif_thumbnail_to_file(const char *path, unsigned int thumb_w, unsigned int thumb_h, const char *thumb_path)
+{
+ int err = MS_MEDIA_ERR_NONE;
+ mm_util_image_h decode_image = NULL;
+
+ err = mm_util_decode_from_gif_file(path, &decode_image);
+ thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_decode_from_gif_file failed : %d", err);
+
+ err = mm_util_resize_B_P(decode_image, thumb_w, thumb_h, thumb_path);
+ mm_image_destroy_image(decode_image);
+ thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_resize_B_P failed : %d", err);
return MS_MEDIA_ERR_NONE;
}
+static int __create_gif_thumbnail_to_buffer(const char *path, unsigned int thumb_w, unsigned int thumb_h, mm_util_image_h *thumbnail)
+{
+ int err = MS_MEDIA_ERR_NONE;
+ mm_util_image_h decode_image = NULL;
+ mm_util_image_h rgba_thumbnail = NULL;
+
+ err = mm_util_decode_from_gif_file(path, &decode_image);
+ thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_decode_from_gif_file failed : %d", err);
+
+ err = mm_util_resize_B_B(decode_image, thumb_w, thumb_h, &rgba_thumbnail);
+ mm_image_destroy_image(decode_image);
+ thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_resize_B_B failed : %d", err);
+
+ err = mm_util_convert_B_B(rgba_thumbnail, MM_UTIL_COLOR_BGRA, thumbnail);
+ mm_image_destroy_image(rgba_thumbnail);
+ thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_convert_B_B failed : %d", err);
+
+ return MS_MEDIA_ERR_NONE;
+}
+
+static int __decode_jpeg_with_downscale(const char *path, size_t image_size, size_t thumb_size, mm_util_image_h *decode_image)
+{
+ mm_util_jpeg_decode_downscale downscale = MM_UTIL_JPEG_DECODE_DOWNSCALE_1_1;
+
+ // The downscale divide each width & height, so we should use squares 4(2*2), 16(4*4), 64(8*8).
+ if ((image_size >= thumb_size * 4) && (image_size < thumb_size * 16))
+ downscale = MM_UTIL_JPEG_DECODE_DOWNSCALE_1_2;
+ else if ((image_size >= thumb_size * 16) && (image_size < thumb_size * 64))
+ downscale = MM_UTIL_JPEG_DECODE_DOWNSCALE_1_4;
+ else if (image_size >= thumb_size * 64)
+ downscale = MM_UTIL_JPEG_DECODE_DOWNSCALE_1_8;
+
+ thumb_info("downscale: %d", downscale);
+
+ return mm_util_decode_from_jpeg_file(path, MM_UTIL_COLOR_BGRA, downscale, decode_image);
+}
+
+static int __create_jpeg_thumbnail_to_file(const char *path, size_t image_size, unsigned int thumb_w, unsigned int thumb_h, const char *thumb_path, bool auto_rotate)
+{
+ int err = MS_MEDIA_ERR_NONE;
+ mm_util_image_h decode_image = NULL;
+ mm_util_image_h resize_image = NULL;
+ mm_util_rotate_type_e rotation = __get_image_orientation(path);
+
+ err = __decode_jpeg_with_downscale(path, image_size, (size_t)(thumb_w * thumb_h), &decode_image);
+ thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_decode_from_jpeg_file failed : %d", err);
+
+ if (auto_rotate && (rotation != MM_UTIL_ROTATE_0)) {
+ err = mm_util_resize_B_B(decode_image, thumb_w, thumb_h, &resize_image);
+ mm_image_destroy_image(decode_image);
+ thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_resize_B_B failed : %d", err);
+
+ err = mm_util_rotate_B_P(resize_image, rotation, thumb_path);
+ mm_image_destroy_image(resize_image);
+ thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_rotate_B_P failed : %d", err);
+ } else {
+ err = mm_util_resize_B_P(decode_image, thumb_w, thumb_h, thumb_path);
+ mm_image_destroy_image(decode_image);
+ thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_resize_B_P failed : %d", err);
+ }
+
+ return MS_MEDIA_ERR_NONE;
+}
+
+static int __create_jpeg_thumbnail_to_buffer(const char *path, size_t image_size, unsigned int thumb_w, unsigned int thumb_h, mm_util_image_h *thumbnail)
+{
+ int err = MS_MEDIA_ERR_NONE;
+ mm_util_image_h decode_image = NULL;
+
+ err = __decode_jpeg_with_downscale(path, image_size, (size_t)(thumb_w * thumb_h), &decode_image);
+ thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_decode_from_jpeg_file failed : %d", err);
+
+ err = mm_util_resize_B_B(decode_image, thumb_w, thumb_h, thumbnail);
+ mm_image_destroy_image(decode_image);
+ thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_resize_B_B failed : %d", err);
+
+ return MS_MEDIA_ERR_NONE;
+}
+#endif
+
int create_image_thumbnail_to_file(const char *path, unsigned int width, unsigned int height, const char *thumb_path, bool auto_rotate)
{
int err = MS_MEDIA_ERR_NONE;
+ unsigned int image_w = 0;
+ unsigned int image_h = 0;
unsigned int thumb_w = width;
unsigned int thumb_h = height;
+ mm_util_img_codec_type image_type = 0;
err = __check_parameter_validity_for_file(path, width, height, thumb_path);
thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "Invalid parameter");
- err = __adjust_thumb_ratio(path, &thumb_w, &thumb_h);
+ err = __adjust_thumb_ratio(path, &thumb_w, &thumb_h, &image_w, &image_h, &image_type);
thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "__adjust_thumb_ratio failed");
+#if defined(USE_MEMORY_USAGE_REDUCTION)
+ if (image_type == IMG_CODEC_GIF)
+ return __create_gif_thumbnail_to_file(path, thumb_w, thumb_h, thumb_path);
+ else if (image_type == IMG_CODEC_JPEG)
+ return __create_jpeg_thumbnail_to_file(path, (size_t)(image_w * image_h), thumb_w, thumb_h, thumb_path, auto_rotate);
+#endif
+
if (auto_rotate)
err = mm_util_resize_and_rotate_P_P(path, thumb_w, thumb_h, thumb_path);
else
int create_image_thumbnail_to_buffer(const char *path, unsigned int width, unsigned int height, unsigned char **thumb_buffer, size_t *thumb_size, unsigned int *thumb_width, unsigned int *thumb_height)
{
int err = MS_MEDIA_ERR_NONE;
+ unsigned int image_w = 0;
+ unsigned int image_h = 0;
unsigned int thumb_w = width;
unsigned int thumb_h = height;
mm_util_image_h img = NULL;
+ mm_util_img_codec_type image_type = 0;
err = __check_parameter_validity_for_buffer(path, width, height, thumb_buffer, thumb_size, thumb_width, thumb_height);
thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "Invalid parameter");
- err = __adjust_thumb_ratio(path, &thumb_w, &thumb_h);
+ err = __adjust_thumb_ratio(path, &thumb_w, &thumb_h, &image_w, &image_h, &image_type);
thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "__adjust_thumb_ratio failed");
- err = mm_util_resize_P_B(path, thumb_w, thumb_h, MM_UTIL_COLOR_BGRA, &img);
- thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_resize_P_B failed : %d", err);
+#if defined(USE_MEMORY_USAGE_REDUCTION)
+ if (image_type == IMG_CODEC_GIF) {
+ err = __create_gif_thumbnail_to_buffer(path, thumb_w, thumb_h, &img);
+ thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "__create_gif_thumbnail_to_buffer failed : %d", err);
+ } else if (image_type == IMG_CODEC_JPEG) {
+ err = __create_jpeg_thumbnail_to_buffer(path, (size_t)(image_w * image_h), thumb_w, thumb_h, &img);
+ thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "__create_jpeg_thumbnail_to_buffer failed : %d", err);
+ } else
+#endif
+ {
+ err = mm_util_resize_P_B(path, thumb_w, thumb_h, MM_UTIL_COLOR_BGRA, &img);
+ thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_resize_P_B failed : %d", err);
+ }
err = mm_image_get_image(img, thumb_width, thumb_height, NULL, thumb_buffer, thumb_size);
}
return create_video_thumbnail_to_file(path, width, height, thumb_path, false);
-}
\ No newline at end of file
+}