An example of using libexif to set JPEG Orientation Tag
来源:互联网 发布:天界翅膀进阶数据 编辑:程序博客网 时间:2024/05/16 17:43
An example of using libexif to set JPEG Orientation Tag :http://www.jwz.org/blog/2008/12/cocoa-exif-rotation/
#include <stdio.h>#include <stdlib.h>#include <libexif/exif-data.h>intmain(int argc, char *argv[]) { if(argc != 2) { printf("Usage: foo <image>\n"); exit(1); } int orientation = 0; ExifData *exifData = exif_data_new_from_file(argv[1]); if (exifData) { ExifByteOrder byteOrder = exif_data_get_byte_order(exifData); ExifEntry *exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION); if (exifEntry) orientation = exif_get_short(exifEntry->data, byteOrder); exif_data_free(exifData); } /* 0th Row 0th Column 1 top left side 2 top right side 3 bottom right side 4 bottom left side 5 left side top 6 right side top 7 right side bottom 8 left side bottom */ if(orientation != 0) { printf("orientation == %d\n", orientation); } exit(0);}
在Github上找到了一个不错的代码,但本人能力有限,还未曾看懂,希望高手看懂后能给解释下。
BTW,关于Exif orientation Tag,有个非常详尽的资料:http://sylvana.net/jpegcrop/exif_orientation.html
(介绍各个方向所对应的tag的值)
- <span style="font-size: 14px;">/*
- * jpegtran.c
- *
- * Copyright (C) 1995-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * plenty of changes by Gerd Hoffmann <kraxel@bytesex.org>, with focus on
- * digital image processing and sane exif handling:
- *
- * - does transformations only (flip/rotate/transpose/transverse).
- * - also transforms the exif thumbnail if present.
- * - can automatically figure transformation from the
- * exif orientation tag.
- * - updates the exif orientation tag.
- * - updates the exif pixel dimension tags.
- *
- * This file contains a command-line user interface for JPEG transcoding.
- * It is very similar to cjpeg.c, but provides lossless transcoding between
- * different JPEG file formats. It also provides some lossless and sort-of-
- * lossless transformations of JPEG data.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <stddef.h>
- #include <unistd.h>
- #include <errno.h>
- #include <string.h>
- #include <utime.h>
- #include <setjmp.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <jpeglib.h>
- #include "transupp.h" /* Support routines for jpegtran */
- #include "jpegtools.h"
- #include "misc.h"
- #include <libexif/exif-data.h>
- #include <libexif/exif-utils.h>
- #include <libexif/exif-ifd.h>
- #include <libexif/exif-tag.h>
- static int do_transform(struct jpeg_decompress_struct *src,
- struct jpeg_compress_struct *dst,
- JXFORM_CODE transform,
- unsigned char *comment,
- char *thumbnail, int tsize,
- unsigned int flags);
- static JXFORM_CODE transmagic[] = {
- [ 1 ] = JXFORM_NONE,
- [ 2 ] = JXFORM_FLIP_H,
- [ 3 ] = JXFORM_ROT_180,
- [ 4 ] = JXFORM_FLIP_V,
- [ 5 ] = JXFORM_TRANSPOSE,
- [ 6 ] = JXFORM_ROT_90,
- [ 7 ] = JXFORM_TRANSVERSE,
- [ 8 ] = JXFORM_ROT_270,
- };
- #if 0
- static char *transname[] = {
- [ JXFORM_NONE ] = "none",
- [ JXFORM_FLIP_H ] = "flip h",
- [ JXFORM_FLIP_V ] = "flip v",
- [ JXFORM_TRANSPOSE ] = "transpose",
- [ JXFORM_TRANSVERSE ] = "transverse",
- [ JXFORM_ROT_90 ] = "rot 90",
- [ JXFORM_ROT_180 ] = "rot 190",
- [ JXFORM_ROT_270 ] = "rot 270",
- };
- #endif
- /* ---------------------------------------------------------------------- */
- /* libjpeg error handler -- exit via longjump */
- struct longjmp_error_mgr {
- struct jpeg_error_mgr jpeg;
- jmp_buf setjmp_buffer;
- };
- static void longjmp_error_exit(j_common_ptr cinfo)
- {
- struct longjmp_error_mgr *h = (struct longjmp_error_mgr*)cinfo->err;
- (*cinfo->err->output_message)(cinfo);
- longjmp(h->setjmp_buffer, 1);
- }
- /* ---------------------------------------------------------------------- */
- static long get_int(ExifData *ed, ExifEntry *ee)
- {
- ExifByteOrder o = exif_data_get_byte_order(ed);
- long value;
- switch (ee->format) {
- case EXIF_FORMAT_SHORT:
- value = exif_get_short (ee->data, o);
- break;
- case EXIF_FORMAT_LONG:
- value = exif_get_long (ee->data, o);
- break;
- case EXIF_FORMAT_SLONG:
- value = exif_get_slong (ee->data, o);
- break;
- default:
- fprintf(stderr,"get_int oops\n");
- exit(1);
- }
- return value;
- }
- static void set_int(ExifData *ed, ExifEntry *ee,long value)
- {
- ExifByteOrder o = exif_data_get_byte_order(ed);
- switch (ee->format) {
- case EXIF_FORMAT_SHORT:
- exif_set_short (ee->data, o, value);
- break;
- case EXIF_FORMAT_LONG:
- exif_set_long (ee->data, o, value);
- break;
- case EXIF_FORMAT_SLONG:
- exif_set_slong (ee->data, o, value);
- break;
- default:
- fprintf(stderr,"set_int oops\n");
- exit(1);
- }
- }
- static void update_orientation(ExifData *ed,int ifd, int orientation)
- {
- ExifEntry *ee;
- ee = exif_content_get_entry(ed->ifd[ifd], 0x0112);
- if (NULL == ee)
- return;
- set_int(ed,ee,orientation);
- }
- static void update_dimension(ExifData *ed, JXFORM_CODE transform,
- int src_x,int src_y)
- {
- static struct {
- int idf;
- int tag;
- int x;
- } fields[] = {
- {
- .idf = EXIF_IFD_EXIF,
- .tag = EXIF_TAG_PIXEL_X_DIMENSION,
- .x = 1,
- },{
- .idf = EXIF_IFD_EXIF,
- .tag = EXIF_TAG_PIXEL_Y_DIMENSION,
- .x = 0,
- },{
- .idf = EXIF_IFD_INTEROPERABILITY,
- .tag = EXIF_TAG_RELATED_IMAGE_WIDTH,
- .x = 1,
- },{
- .idf = EXIF_IFD_INTEROPERABILITY,
- .tag = EXIF_TAG_RELATED_IMAGE_LENGTH,
- .x = 0,
- }
- };
- ExifEntry *ee;
- int i;
- for (i = 0; i < sizeof(fields)/sizeof(fields[0]); i++) {
- ee = exif_content_get_entry(ed->ifd[fields[i].idf], fields[i].tag);
- if (!ee)
- continue;
- switch (transform) {
- case JXFORM_ROT_90:
- case JXFORM_ROT_270:
- case JXFORM_TRANSPOSE:
- case JXFORM_TRANSVERSE:
- /* x/y reversed */
- set_int(ed, ee, fields[i].x ? src_y : src_x);
- break;
- default:
- /* normal */
- set_int(ed, ee, fields[i].x ? src_x : src_y);
- break;
- }
- }
- }
- static int get_orientation(ExifData *ed)
- {
- ExifEntry *ee;
- ee = exif_content_get_entry(ed->ifd[EXIF_IFD_0], 0x0112);
- if (NULL == ee)
- return 1; /* top - left */
- return get_int(ed,ee);
- }
- /* ---------------------------------------------------------------------- */
- struct th {
- struct jpeg_decompress_struct src;
- struct jpeg_compress_struct dst;
- struct jpeg_error_mgr jsrcerr, jdsterr;
- unsigned char *in;
- unsigned char *out;
- int isize, osize;
- };
- static void thumbnail_src_init(struct jpeg_decompress_struct *cinfo)
- {
- struct th *h = container_of(cinfo,struct th, src);
- cinfo->src->next_input_byte = h->in;
- cinfo->src->bytes_in_buffer = h->isize;
- }
- static int thumbnail_src_fill(struct jpeg_decompress_struct *cinfo)
- {
- fprintf(stderr,"jpeg: panic: no more thumbnail input data\n");
- exit(1);
- }
- static void thumbnail_src_skip(struct jpeg_decompress_struct *cinfo,
- long num_bytes)
- {
- cinfo->src->next_input_byte += num_bytes;
- }
- static void thumbnail_src_term(struct jpeg_decompress_struct *cinfo)
- {
- /* nothing */
- }
- static void thumbnail_dest_init(struct jpeg_compress_struct *cinfo)
- {
- struct th *h = container_of(cinfo,struct th, dst);
- h->osize = h->isize * 2;
- h->out = malloc(h->osize);
- cinfo->dest->next_output_byte = h->out;
- cinfo->dest->free_in_buffer = h->osize;
- }
- static boolean thumbnail_dest_flush(struct jpeg_compress_struct *cinfo)
- {
- fprintf(stderr,"jpeg: panic: output buffer full\n");
- exit(1);
- }
- static void thumbnail_dest_term(struct jpeg_compress_struct *cinfo)
- {
- struct th *h = container_of(cinfo,struct th, dst);
- h->osize -= cinfo->dest->free_in_buffer;
- }
- static struct jpeg_source_mgr thumbnail_src = {
- .init_source = thumbnail_src_init,
- .fill_input_buffer = thumbnail_src_fill,
- .skip_input_data = thumbnail_src_skip,
- .resync_to_restart = jpeg_resync_to_restart,
- .term_source = thumbnail_src_term,
- };
- static struct jpeg_destination_mgr thumbnail_dst = {
- .init_destination = thumbnail_dest_init,
- .empty_output_buffer = thumbnail_dest_flush,
- .term_destination = thumbnail_dest_term,
- };
- static void do_thumbnail(ExifData *ed, JXFORM_CODE transform)
- {
- struct th th;
- if (JXFORM_NONE == transform)
- return;
- memset(&th,0,sizeof(th));
- th.in = ed->data;
- th.isize = ed->size;
- /* setup src */
- th.src.err = jpeg_std_error(&th.jsrcerr);
- jpeg_create_decompress(&th.src);
- th.src.src = &thumbnail_src;
- /* setup dst */
- th.dst.err = jpeg_std_error(&th.jdsterr);
- jpeg_create_compress(&th.dst);
- th.dst.dest = &thumbnail_dst;
- /* transform image */
- do_transform(&th.src,&th.dst,transform,NULL,NULL,0,JFLAG_TRANSFORM_IMAGE);
- /* cleanup */
- jpeg_destroy_decompress(&th.src);
- jpeg_destroy_compress(&th.dst);
- /* replace thumbnail */
- free(ed->data);
- ed->data = th.out;
- ed->size = th.osize;
- }
- static void do_exif(struct jpeg_decompress_struct *src,
- JXFORM_CODE *transform,
- char *thumbnail,int tsize,
- unsigned int flags)
- {
- jpeg_saved_marker_ptr mark;
- ExifData *ed = NULL;
- unsigned char *data;
- unsigned int size;
- for (mark = src->marker_list; NULL != mark; mark = mark->next) {
- if (mark->marker != JPEG_APP0 +1)
- continue;
- ed = exif_data_new_from_data(mark->data,mark->data_length);
- break;
- }
- if (flags & JFLAG_UPDATE_THUMBNAIL) {
- if (NULL == ed)
- ed = exif_data_new();
- if (NULL == mark) {
- mark = src->mem->alloc_large((j_common_ptr)src,JPOOL_IMAGE,sizeof(*mark));
- memset(mark,0,sizeof(*mark));
- mark->marker = JPEG_APP0 +1;
- mark->next = src->marker_list;
- src->marker_list = mark;
- }
- if (ed->data)
- free(ed->data);
- ed->data = thumbnail;
- ed->size = tsize;
- }
- if (NULL == ed)
- return;
- if (-1 == *transform) {
- /* automagic image transformation */
- int orientation = get_orientation(ed);
- *transform = JXFORM_NONE;
- if (orientation >= 1 && orientation <= 8)
- *transform = transmagic[orientation];
- #if 0
- if (debug)
- fprintf(stderr,"autotrans: %s\n",transname[*transform]);
- #endif
- }
- /* update exif data */
- if (flags & JFLAG_UPDATE_ORIENTATION) {
- update_orientation(ed,EXIF_IFD_0,1);
- update_orientation(ed,EXIF_IFD_1,1);
- }
- if (ed->data && ed->data[0] == 0xff && ed->data[1] == 0xd8 &&
- (flags & JFLAG_TRANSFORM_THUMBNAIL))
- do_thumbnail(ed,*transform);
- update_dimension(ed, (flags & JFLAG_TRANSFORM_IMAGE) ? *transform : JXFORM_NONE,
- src->image_width, src->image_height);
- /* build new exif data block */
- exif_data_save_data(ed,&data,&size);
- exif_data_unref(ed);
- /* update jpeg APP1 (EXIF) marker */
- mark->data = src->mem->alloc_large((j_common_ptr)src,JPOOL_IMAGE,size);
- mark->original_length = size;
- mark->data_length = size;
- memcpy(mark->data,data,size);
- free(data);
- }
- /* ---------------------------------------------------------------------- */
- static void do_comment(struct jpeg_decompress_struct *src,
- unsigned char *comment)
- {
- jpeg_saved_marker_ptr mark;
- int size;
- /* find or create comment marker */
- for (mark = src->marker_list;; mark = mark->next) {
- if (mark->marker == JPEG_COM)
- break;
- if (NULL == mark->next) {
- mark->next = src->mem->alloc_large((j_common_ptr)src,JPOOL_IMAGE,
- sizeof(*mark));
- mark = mark->next;
- memset(mark,0,sizeof(*mark));
- mark->marker = JPEG_COM;
- break;
- }
- }
- /* update comment marker */
- size = strlen(comment) +1;
- mark->data = src->mem->alloc_large((j_common_ptr)src,JPOOL_IMAGE,size);
- mark->original_length = size;
- mark->data_length = size;
- memcpy(mark->data,comment,size);
- }
- static int do_transform(struct jpeg_decompress_struct *src,
- struct jpeg_compress_struct *dst,
- JXFORM_CODE transform,
- unsigned char *comment,
- char *thumbnail, int tsize,
- unsigned int flags)
- {
- jvirt_barray_ptr * src_coef_arrays;
- jvirt_barray_ptr * dst_coef_arrays;
- jpeg_transform_info transformoption;
- jcopy_markers_setup(src, JCOPYOPT_ALL);
- if (JPEG_HEADER_OK != jpeg_read_header(src, TRUE))
- return -1;
- do_exif(src,&transform,thumbnail,tsize,flags);
- if (-1 == transform)
- transform = JXFORM_NONE;
- if (!(flags & JFLAG_TRANSFORM_IMAGE))
- transform = JXFORM_NONE;
- if ((flags & JFLAG_UPDATE_COMMENT) && NULL != comment)
- do_comment(src,comment);
- memset(&transformoption,0,sizeof(transformoption));
- transformoption.transform = transform;
- transformoption.trim = FALSE;
- transformoption.force_grayscale = FALSE;
- /* Any space needed by a transform option must be requested before
- * jpeg_read_coefficients so that memory allocation will be done right.
- */
- jtransform_request_workspace(src, &transformoption);
- src_coef_arrays = jpeg_read_coefficients(src);
- jpeg_copy_critical_parameters(src, dst);
- dst_coef_arrays = jtransform_adjust_parameters
- (src, dst, src_coef_arrays, &transformoption);
- /* Start compressor (note no image data is actually written here) */
- jpeg_write_coefficients(dst, dst_coef_arrays);
- /* Copy to the output file any extra markers that we want to preserve */
- jcopy_markers_execute(src, dst, JCOPYOPT_ALL);
- /* Execute image transformation, if any */
- jtransform_execute_transformation(src, dst,
- src_coef_arrays,
- &transformoption);
- /* Finish compression and release memory */
- jpeg_finish_compress(dst);
- jpeg_finish_decompress(src);
- return 0;
- }
- /* ---------------------------------------------------------------------- */
- int jpeg_transform_fp(FILE *in,FILE *out,
- JXFORM_CODE transform,
- unsigned char *comment,
- char *thumbnail, int tsize,
- unsigned int flags)
- {
- struct jpeg_decompress_struct src;
- struct jpeg_compress_struct dst;
- struct jpeg_error_mgr jdsterr;
- struct longjmp_error_mgr jsrcerr;
- /* setup src */
- src.err = jpeg_std_error(&jsrcerr.jpeg);
- jsrcerr.jpeg.error_exit = longjmp_error_exit;
- if (setjmp(jsrcerr.setjmp_buffer))
- /* something went wrong within the jpeg library ... */
- goto oops;
- jpeg_create_decompress(&src);
- jpeg_stdio_src(&src, in);
- /* setup dst */
- dst.err = jpeg_std_error(&jdsterr);
- jpeg_create_compress(&dst);
- jpeg_stdio_dest(&dst, out);
- /* transform image */
- do_transform(&src,&dst,transform,comment,thumbnail,tsize,flags);
- /* cleanup */
- jpeg_destroy_decompress(&src);
- jpeg_destroy_compress(&dst);
- return 0;
- oops:
- jpeg_destroy_decompress(&src);
- jpeg_destroy_compress(&dst);
- return -1;
- }
- int jpeg_transform_files(char *infile,char *outfile,
- JXFORM_CODE transform,
- unsigned char *comment,
- char *thumbnail,int tsize,
- unsigned int flags)
- {
- int rc;
- FILE *in;
- FILE *out;
- /* open infile */
- in = fopen(infile,"r");
- if (NULL == in) {
- fprintf(stderr,"open %s: %s\n",infile,strerror(errno));
- return -1;
- }
- /* open outfile */
- out = fopen(outfile,"w");
- if (NULL == out) {
- fprintf(stderr,"open %s: %s\n",outfile,strerror(errno));
- fclose(in);
- return -1;
- }
- /* go! */
- rc = jpeg_transform_fp(in,out,transform,comment,thumbnail,tsize,flags);
- fclose(in);
- fclose(out);
- return rc;
- }
- int jpeg_transform_inplace(char *file,
- JXFORM_CODE transform,
- unsigned char *comment,
- char *thumbnail, int tsize,
- unsigned int flags)
- {
- char *tmpfile;
- char *bakfile;
- struct stat st;
- int fd;
- FILE *in = NULL;
- FILE *out = NULL;
- /* are we allowed to write to the file? */
- if (0 != access(file,W_OK)) {
- fprintf(stderr,"access %s: %s\n",file,strerror(errno));
- return -1;
- }
- /* open infile */
- in = fopen(file,"r");
- if (NULL == in) {
- fprintf(stderr,"open %s: %s\n",file,strerror(errno));
- return -1;
- }
- /* open tmpfile */
- tmpfile = malloc(strlen(file)+10);
- sprintf(tmpfile,"%s.XXXXXX",file);
- fd = mkstemp(tmpfile);
- if (-1 == fd) {
- fprintf(stderr,"mkstemp(%s): %s\n",tmpfile,strerror(errno));
- goto oops;
- }
- out = fdopen(fd,"w");
- /* copy owner and permissions */
- if (-1 == fstat(fileno(in),&st)) {
- fprintf(stderr,"fstat(%s): %s\n",file,strerror(errno));
- // goto oops;
- }
- if (-1 == fchown(fileno(out),st.st_uid,st.st_gid)) {
- fprintf(stderr,"fchown(%s): %s\n",tmpfile,strerror(errno));
- // goto oops;
- }
- if (-1 == fchmod(fileno(out),st.st_mode)) {
- fprintf(stderr,"fchmod(%s): %s\n",tmpfile,strerror(errno));
- // goto oops;
- }
- /* transform */
- if (0 != jpeg_transform_fp(in,out,transform,comment,thumbnail,tsize,flags))
- goto oops;
- /* worked ok -- commit */
- fclose(in);
- fclose(out);
- if (flags & JFLAG_FILE_BACKUP) {
- bakfile = malloc(strlen(file)+2);
- sprintf(bakfile,"%s~",file);
- rename(file,bakfile);
- free(bakfile);
- }
- rename(tmpfile,file);
- if (flags & JFLAG_FILE_KEEP_TIME) {
- struct utimbuf u;
- u.actime = st.st_atime;
- u.modtime = st.st_mtime;
- utime(file,&u);
- }
- /* cleanup & return */
- free(tmpfile);
- return 0;
- oops:
- /* something went wrong -- rollback */
- if (in)
- fclose(in);
- if (out) {
- fclose(out);
- unlink(tmpfile);
- }
- return -1;
- }</span>
0 0
- An example of using libexif to set JPEG Orientation Tag
- An example of using libexif to set JPEG Orientation Tag
- an example of using automake.
- An example of using Thrift
- An easy example of using AJAX
- An example of using STL multimap
- An example of how to streaming audio over network using Qt
- How to sort an arbitrarily large set of data using Hadoop?
- an example of drawing beast tree using ggtree
- JPEG Orientation
- an example of repeater
- An example of delegate Command to yet another Command.
- An example of how to do a simulation by LAMMPS
- Object reference not set to an instance of an object.
- Object reference not set to an instance of an object.
- Object reference not set to an instance of an object
- a complete example of using One to Many and One to One associations using MyBatis annotations
- How to set Android camera orientation properly?
- [VC/MFC]滑动动条控件Slider的用法
- Android EXIF
- 浅析Android下的Android.mk文件
- 我的Android进阶之旅------>Android疯狂连连看游戏的实现之开发游戏界面(二)
- p03
- An example of using libexif to set JPEG Orientation Tag
- 5 Simple Things That Can Help Change Your Attitude
- http中的mine
- 我的Android进阶之旅------>Android疯狂连连看游戏的实现之开发游戏界面(二)
- JS规范
- 7 WARNING Signs You Chose the Wrong Job
- S3C2440 TFTLCD驱动详解
- Xcode6:No architectures to compile for(ONLY_ACTIVE_ARCH=YES...)
- 我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)