/* * Copyright 2012 Samsung Electronics Co., Ltd * * Licensed under the Flora License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://floralicense.org/license/ * * 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 "cam_debug.h" #include "cam_exif_info.h" #include #include //#include static void _set_uint16 (int is_motorola, void * out, unsigned short in) { if (is_motorola) { ((unsigned char *)out)[0] = in & 0x00ff; ((unsigned char *)out)[1] = in >> 8; } else { ((unsigned char *)out)[0] = in >> 8; ((unsigned char *)out)[1] = in & 0x00ff; } } ExifData* cam_exif_get_exif_from_data(unsigned char *data, unsigned int data_size) { ExifData *exif = NULL; ExifLoader *loader = NULL; unsigned char size[2]; unsigned int i; loader = exif_loader_new(); if (loader != NULL) { size[0] = (unsigned char) (data_size); size[1] = (unsigned char) (data_size >> 8); exif_loader_write (loader, size, 2); for (i = 0; i < data_size && exif_loader_write (loader, data + i, 1); i++); exif = exif_loader_get_data (loader); if (exif == NULL) cam_critical(LOG_CAM, "exif_loader_get_data() fail"); exif_loader_unref (loader); } else cam_critical(LOG_CAM, "exif_loader_new() fail"); return exif; } gboolean cam_exif_set_entry(ExifData *in_exif, ExifIfd ifd, ExifTag tag, ExifFormat format, unsigned long components, unsigned char *data) { ExifData *exif = (ExifData *)in_exif; ExifEntry *entry = NULL; if (in_exif == NULL || format <= 0 || components <= 0 || data == NULL) { cam_critical(LOG_CAM, "invalid input!! (exif:%p format:%d component=%lu data:%p)", in_exif, format, components, data); return FALSE; } exif_content_remove_entry(exif->ifd[ifd], exif_content_get_entry(exif->ifd[ifd], tag)); entry = exif_entry_new(); if (entry == NULL) { cam_critical(LOG_CAM, "exif_entry_new() return NULL"); return FALSE; } exif_entry_initialize(entry, tag); entry->tag = tag; entry->format = format; entry->components = components; if (entry->size == 0) { entry->data = NULL; entry->data = malloc(exif_format_get_size(format) * entry->components); if (!entry->data) { exif_entry_unref(entry); cam_critical(LOG_CAM, "entry->data malloc fail"); return FALSE; } if (format == EXIF_FORMAT_ASCII) { memset(entry->data, '\0', exif_format_get_size(format) * entry->components); } } entry->size = exif_format_get_size(format) * entry->components; memcpy(entry->data,data,entry->size); exif_content_add_entry(exif->ifd[ifd], entry); exif_entry_unref(entry); return TRUE; } gboolean cam_exif_get_data_from_exif(unsigned char *out_data, unsigned int out_size, ExifData *in_exif) { unsigned char *exif_raw = NULL; unsigned int size = 0; if (in_exif == NULL) { cam_critical(LOG_CAM, "in_exif is NULL"); return FALSE; } cam_debug(LOG_CAM, "exif->ifd:%p", in_exif->ifd); exif_data_save_data(in_exif, &exif_raw, &size); if (exif_raw == NULL) { cam_critical(LOG_CAM, "exif_data_save_data() is fail"); return FALSE; } if (out_data) { free (out_data); out_data = NULL; out_size = 0; } out_data = exif_raw; out_size = size; return TRUE; } gboolean cam_exif_change_thumb_info(unsigned char *exif_raw, unsigned int exif_raw_size, unsigned char *thumb_data , int thumb_w, int thumb_h, unsigned int thumb_size) { ExifData *exif = NULL; static ExifLong elong[10]; unsigned char *p_compressed = NULL; int cntl = 0; exif = cam_exif_get_exif_from_data(exif_raw, exif_raw_size); exif->data = thumb_data; exif->size = thumb_size; // set thumbnail data p_compressed = malloc(sizeof(ExifShort)); if (p_compressed != NULL) { exif_set_short(p_compressed, exif_data_get_byte_order(exif), 6); if (!cam_exif_set_entry(exif, EXIF_IFD_1, EXIF_TAG_COMPRESSION, EXIF_FORMAT_SHORT, 1, p_compressed)) { cam_critical(LOG_CAM, "cam_exif_set_entry(tag:EXIF_TAG_COMPRESSION) fail"); goto exit; } } else { cam_critical(LOG_CAM, "p_compressed is NULL"); goto exit; } // set thumbnail size exif_set_long ((unsigned char *)&elong[cntl], exif_data_get_byte_order(exif), thumb_w); if( !cam_exif_set_entry(exif, EXIF_IFD_1, EXIF_TAG_IMAGE_WIDTH, EXIF_FORMAT_LONG, 1, (unsigned char*)&elong[cntl++])) { cam_critical(LOG_CAM, "cam_exif_set_entry(tag:EXIF_TAG_IMAGE_WIDTH) fail"); goto exit; } exif_set_long ((unsigned char *)&elong[cntl], exif_data_get_byte_order(exif), thumb_h); if (!cam_exif_set_entry(exif, EXIF_IFD_1, EXIF_TAG_IMAGE_LENGTH, EXIF_FORMAT_LONG, 1, (unsigned char*)&elong[cntl++])) { cam_critical(LOG_CAM, "cam_exif_set_entry(tag:EXIF_TAG_IMAGE_LENGTH) fail"); goto exit; } cam_debug(LOG_CAM, "exif:%p exif_size:%d", exif, exif->size); if (!cam_exif_get_data_from_exif (exif_raw, exif_raw_size, exif)) { cam_critical(LOG_CAM, "cam_exif_get_data_from_exif() fail"); goto exit; } exif->data = NULL; exif->size = 0; exif_data_unref (exif); if(p_compressed != NULL) free(p_compressed); p_compressed = NULL; return TRUE; exit : if(p_compressed != NULL) free(p_compressed); p_compressed = NULL; return FALSE; } gboolean cam_exif_write_to_jpeg(unsigned char *in_data, unsigned int in_size, unsigned char *exif_data, unsigned int exif_size ,unsigned char **out_data, unsigned int *out_size) { unsigned char *data = NULL; int data_size = 0; unsigned short head[2] = {0,}; unsigned short head_len = 0; data_size = 2 + 2 + 2 + exif_size + (in_size - 2); data = (unsigned char*)malloc(sizeof(unsigned char)*data_size); if (!data) { cam_critical(LOG_SYS, "alloc fail"); goto exit; } _set_uint16(0, &head[0], 0xffd8); _set_uint16(0, &head[1], 0xffe1); _set_uint16(0, &head_len, (unsigned short)(exif_size + 2)); if (head[0] == 0 || head[1] == 0 || head_len == 0) { cam_critical(LOG_SYS, "set header fail"); goto exit; } // Complete JPEG+EXIF // // SOI marker // memcpy(data, &head[0], 2); //APP1 marker memcpy(data + 2, &head[1], 2); //length of APP1 memcpy(data + 2 + 2, &head_len, 2); //EXIF memcpy(data + 2 + 2 + 2, exif_data, exif_size); //IMAGE memcpy(data + 2 + 2 + 2 + exif_size, in_data + 2, in_size - 2); if (data != NULL) { *out_data = data; *out_size = data_size; } return TRUE; exit: if (data) free(data); data = NULL; return FALSE; }