📄 jpegtools.c
字号:
/* * 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 Knorr <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 "jpeg/transupp.h" /* Support routines for jpegtran */#include "jpegtools.h"#ifdef HAVE_LIBEXIF# include <libexif/exif-data.h># include <libexif/exif-utils.h># include <libexif/exif-ifd.h># include <libexif/exif-tag.h>#endifstatic int do_transform(struct jpeg_decompress_struct *src, struct jpeg_compress_struct *dst, JXFORM_CODE transform, unsigned char *comment, 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 0static 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);}/* ---------------------------------------------------------------------- */#ifdef HAVE_LIBEXIFstatic 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);}/* ---------------------------------------------------------------------- */#define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})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; 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,JFLAG_TRANSFORM_IMAGE); /* cleanup */ jpeg_destroy_decompress(&th.src);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -