1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stddef.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <jpeglib.h>
7 #include <setjmp.h>
8
9 #include <libexif/exif-data.h>
10
11 #include "readers.h"
12 #include "misc.h"
13
14 /* ---------------------------------------------------------------------- */
15 /* load */
16
17 struct jpeg_state {
18 FILE * infile; /* source file */
19
20 struct jpeg_decompress_struct cinfo;
21 struct jpeg_error_mgr jerr;
22 jmp_buf errjump;
23 JSAMPARRAY buffer; /* Output row buffer */
24 int row_stride,linelength; /* physical row width in output buffer */
25 unsigned char *image,*ptr;
26
27 /* thumbnail */
28 unsigned char *thumbnail;
29 unsigned int tpos, tsize;
30 };
31
32 /* ---------------------------------------------------------------------- */
33 /* data source manager for thumbnail images */
34
thumbnail_src_init(struct jpeg_decompress_struct * cinfo)35 static void thumbnail_src_init(struct jpeg_decompress_struct *cinfo)
36 {
37 struct jpeg_state *h = container_of(cinfo, struct jpeg_state, cinfo);
38 cinfo->src->next_input_byte = h->thumbnail;
39 cinfo->src->bytes_in_buffer = h->tsize;
40 }
41
thumbnail_src_fill(struct jpeg_decompress_struct * cinfo)42 static int thumbnail_src_fill(struct jpeg_decompress_struct *cinfo)
43 {
44 fprintf(stderr,"jpeg: panic: no more thumbnail input data\n");
45 exit(1);
46 }
47
thumbnail_src_skip(struct jpeg_decompress_struct * cinfo,long num_bytes)48 static void thumbnail_src_skip(struct jpeg_decompress_struct *cinfo,
49 long num_bytes)
50 {
51 cinfo->src->next_input_byte += num_bytes;
52 }
53
thumbnail_src_term(struct jpeg_decompress_struct * cinfo)54 static void thumbnail_src_term(struct jpeg_decompress_struct *cinfo)
55 {
56 /* nothing */
57 }
58
59 static struct jpeg_source_mgr thumbnail_mgr = {
60 .init_source = thumbnail_src_init,
61 .fill_input_buffer = thumbnail_src_fill,
62 .skip_input_data = thumbnail_src_skip,
63 .resync_to_restart = jpeg_resync_to_restart,
64 .term_source = thumbnail_src_term,
65 };
66
67 /* ---------------------------------------------------------------------- */
68 /* jpeg loader */
69
jerror_exit(j_common_ptr info)70 static void jerror_exit(j_common_ptr info)
71 {
72 struct jpeg_decompress_struct *cinfo = (struct jpeg_decompress_struct *)info;
73 struct jpeg_state *h = container_of(cinfo, struct jpeg_state, cinfo);
74 cinfo->err->output_message(info);
75 longjmp(h->errjump, 1);
76 jpeg_destroy_decompress(cinfo);
77 exit(1);
78 }
79
80 static void*
jpeg_init(FILE * fp,char * filename,unsigned int page,struct ida_image_info * i,int thumbnail)81 jpeg_init(FILE *fp, char *filename, unsigned int page,
82 struct ida_image_info *i, int thumbnail)
83 {
84 struct jpeg_state *h;
85 jpeg_saved_marker_ptr mark;
86
87 h = malloc(sizeof(*h));
88 memset(h,0,sizeof(*h));
89 h->infile = fp;
90
91 h->cinfo.err = jpeg_std_error(&h->jerr);
92 h->cinfo.err->error_exit = jerror_exit;
93 if(setjmp(h->errjump))
94 return 0;
95
96 jpeg_create_decompress(&h->cinfo);
97 jpeg_save_markers(&h->cinfo, JPEG_COM, 0xffff); /* comment */
98 jpeg_save_markers(&h->cinfo, JPEG_APP0+1, 0xffff); /* EXIF */
99 jpeg_stdio_src(&h->cinfo, h->infile);
100 jpeg_read_header(&h->cinfo, TRUE);
101
102 for (mark = h->cinfo.marker_list; NULL != mark; mark = mark->next) {
103 switch (mark->marker) {
104 case JPEG_COM:
105 if (debug)
106 fprintf(stderr,"jpeg: comment found (COM marker) [%.*s]\n",
107 (int)mark->data_length, mark->data);
108 load_add_extra(i,EXTRA_COMMENT,mark->data,mark->data_length);
109 break;
110 case JPEG_APP0 +1:
111 if (debug)
112 fprintf(stderr,"jpeg: exif data found (APP1 marker)\n");
113 load_add_extra(i,EXTRA_COMMENT,mark->data,mark->data_length);
114
115 if (thumbnail) {
116 ExifData *ed;
117
118 ed = exif_data_new_from_data(mark->data,mark->data_length);
119 if (ed->data &&
120 ed->data[0] == 0xff &&
121 ed->data[1] == 0xd8) {
122 if (debug)
123 fprintf(stderr,"jpeg: exif thumbnail found\n");
124
125 /* save away thumbnail data */
126 h->thumbnail = malloc(ed->size);
127 h->tsize = ed->size;
128 memcpy(h->thumbnail,ed->data,ed->size);
129 }
130 exif_data_unref(ed);
131 }
132 break;
133 }
134 }
135
136 if (h->thumbnail) {
137 /* save image size */
138 i->thumbnail = 1;
139 i->real_width = h->cinfo.image_width;
140 i->real_height = h->cinfo.image_height;
141
142 /* re-setup jpeg */
143 jpeg_destroy_decompress(&h->cinfo);
144 fclose(h->infile);
145 h->infile = NULL;
146 jpeg_create_decompress(&h->cinfo);
147 h->cinfo.src = &thumbnail_mgr;
148 jpeg_read_header(&h->cinfo, TRUE);
149 }
150
151 h->cinfo.out_color_space = JCS_RGB;
152 jpeg_start_decompress(&h->cinfo);
153 i->width = h->cinfo.image_width;
154 i->height = h->cinfo.image_height;
155 i->npages = 1;
156 switch (h->cinfo.density_unit) {
157 case 0: /* unknown */
158 break;
159 case 1: /* dot per inch */
160 i->dpi = h->cinfo.X_density;
161 break;
162 case 2: /* dot per cm */
163 i->dpi = res_cm_to_inch(h->cinfo.X_density);
164 break;
165 }
166
167 return h;
168 }
169
170 static void
jpeg_read(unsigned char * dst,unsigned int line,void * data)171 jpeg_read(unsigned char *dst, unsigned int line, void *data)
172 {
173 struct jpeg_state *h = data;
174 JSAMPROW row = dst;
175
176 if(setjmp(h->errjump))
177 return;
178 jpeg_read_scanlines(&h->cinfo, &row, 1);
179 }
180
181 static void
jpeg_done(void * data)182 jpeg_done(void *data)
183 {
184 struct jpeg_state *h = data;
185
186 if (setjmp(h->errjump))
187 return;
188 jpeg_destroy_decompress(&h->cinfo);
189 if (h->infile)
190 fclose(h->infile);
191 if (h->thumbnail)
192 free(h->thumbnail);
193 free(h);
194 }
195
196 struct ida_loader jpeg_loader = {
197 magic: "\xff\xd8",
198 moff: 0,
199 mlen: 2,
200 name: "libjpeg",
201 init: jpeg_init,
202 read: jpeg_read,
203 done: jpeg_done,
204 };
205
init_rd(void)206 static void __init init_rd(void)
207 {
208 load_register(&jpeg_loader);
209 }
210