1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stddef.h>
4 #include <unistd.h>
5 #include <errno.h>
6 #include <string.h>
7 
8 #include <jpeglib.h>
9 #include "transupp.h"		/* Support routines for jpegtran */
10 #include "jpegtools.h"
11 
12 #include "misc.h"
13 
14 #include "readers.h"
15 #include "filter.h"
16 #include "genthumbnail.h"
17 
18 /* ---------------------------------------------------------------------- */
19 
20 static struct ida_image*
read_jpeg(char * filename)21 read_jpeg(char *filename)
22 {
23     struct ida_image *img;
24     FILE *fp;
25     unsigned int y;
26     void *data;
27 
28     /* open file */
29     if (NULL == (fp = fopen(filename, "r"))) {
30 	fprintf(stderr,"open %s: %s\n",filename,strerror(errno));
31 	return NULL;
32     }
33 
34     /* load image */
35     img = malloc(sizeof(*img));
36     memset(img,0,sizeof(*img));
37     data = jpeg_loader.init(fp,filename,0,&img->i,0);
38     if (NULL == data) {
39 	fprintf(stderr,"loading %s [%s] FAILED\n",filename,jpeg_loader.name);
40 	free(img);
41 	return NULL;
42     }
43     ida_image_alloc(img);
44     for (y = 0; y < img->i.height; y++)
45   	jpeg_loader.read(ida_image_scanline(img, y), y, data);
46     jpeg_loader.done(data);
47     return img;
48 }
49 
50 /* ---------------------------------------------------------------------- */
51 
52 static struct ida_image*
scale_thumbnail(struct ida_image * src,int max)53 scale_thumbnail(struct ida_image *src, int max)
54 {
55     struct op_resize_parm p;
56     struct ida_rect  rect;
57     struct ida_image *dest;
58     void *data;
59     unsigned int y;
60     float xs,ys,scale;
61 
62     xs = (float)max / src->i.width;
63     ys = (float)max / src->i.height;
64     scale = (xs < ys) ? xs : ys;
65 
66     dest = malloc(sizeof(*dest));
67     memset(dest,0,sizeof(*dest));
68     memset(&rect,0,sizeof(rect));
69     memset(&p,0,sizeof(p));
70 
71     p.width  = src->i.width  * scale;
72     p.height = src->i.height * scale;
73     p.dpi    = src->i.dpi;
74     if (0 == p.width)
75 	p.width = 1;
76     if (0 == p.height)
77 	p.height = 1;
78 
79     data = desc_resize.init(src,&rect,&dest->i,&p);
80     ida_image_alloc(dest);
81     for (y = 0; y < dest->i.height; y++)
82 	desc_resize.work(src, &rect, ida_image_scanline(dest, y), y, data);
83     desc_resize.done(data);
84     return dest;
85 }
86 
87 /* ---------------------------------------------------------------------- */
88 
89 struct thc {
90     struct jpeg_compress_struct dst;
91     struct jpeg_error_mgr err;
92     unsigned char *out;
93     int osize;
94 };
95 
thc_dest_init(struct jpeg_compress_struct * cinfo)96 static void thc_dest_init(struct jpeg_compress_struct *cinfo)
97 {
98     struct thc *h  = container_of(cinfo, struct thc, dst);
99     cinfo->dest->next_output_byte = h->out;
100     cinfo->dest->free_in_buffer   = h->osize;
101 }
102 
thc_dest_flush(struct jpeg_compress_struct * cinfo)103 static boolean thc_dest_flush(struct jpeg_compress_struct *cinfo)
104 {
105     fprintf(stderr,"jpeg: panic: output buffer full\n");
106     exit(1);
107 }
108 
thc_dest_term(struct jpeg_compress_struct * cinfo)109 static void thc_dest_term(struct jpeg_compress_struct *cinfo)
110 {
111     struct thc *h  = container_of(cinfo, struct thc, dst);
112     h->osize -= cinfo->dest->free_in_buffer;
113 }
114 
115 static struct jpeg_destination_mgr thumbnail_dst = {
116     .init_destination    = thc_dest_init,
117     .empty_output_buffer = thc_dest_flush,
118     .term_destination    = thc_dest_term,
119 };
120 
121 static int
compress_thumbnail(struct ida_image * img,char * dest,int max)122 compress_thumbnail(struct ida_image *img, char *dest, int max)
123 {
124     struct thc thc;
125     unsigned int i;
126 
127     memset(&thc,0,sizeof(thc));
128     thc.dst.err = jpeg_std_error(&thc.err);
129     jpeg_create_compress(&thc.dst);
130     thc.dst.dest = &thumbnail_dst;
131     thc.out = dest;
132     thc.osize = max;
133 
134     thc.dst.image_width  = img->i.width;
135     thc.dst.image_height = img->i.height;
136     thc.dst.input_components = 3;
137     thc.dst.in_color_space = JCS_RGB;
138     jpeg_set_defaults(&thc.dst);
139     jpeg_start_compress(&thc.dst, TRUE);
140 
141     for (i = 0; i < img->i.height; i++)
142         jpeg_write_scanlines(&thc.dst, (void*)ida_image_scanline(img, i), 1);
143 
144     jpeg_finish_compress(&(thc.dst));
145     jpeg_destroy_compress(&(thc.dst));
146 
147     return thc.osize;
148 }
149 
150 /* ---------------------------------------------------------------------- */
151 
create_thumbnail(char * filename,unsigned char * dest,int max)152 int create_thumbnail(char *filename, unsigned char *dest, int max)
153 {
154     struct ida_image *img,*thumb;
155     int size;
156 
157     //fprintf(stderr,"%s: read ",filename);
158     img = read_jpeg(filename);
159     if (!img) {
160 	fprintf(stderr,"FAILED\n");
161 	return -1;
162     }
163 
164     //fprintf(stderr,"scale ");
165     thumb = scale_thumbnail(img,160);
166     if (!thumb) {
167 	ida_image_free(img);
168 	free(img);
169 	fprintf(stderr,"FAILED\n");
170 	return -1;
171     }
172 
173     //fprintf(stderr,"compress ");
174     size = compress_thumbnail(thumb,dest,max);
175 
176     /* cleanup */
177     ida_image_free(img);
178     free(img);
179     ida_image_free(thumb);
180     free(thumb);
181     return size;
182 }
183 
184 /* ---------------------------------------------------------------------- */
185 
186 #if 0
187 
188 #define THUMB_MAX 65536
189 
190 static int handle_image(char *filename)
191 {
192     char *dest;
193     int size;
194 
195     dest = malloc(THUMB_MAX);
196     size = create_thumbnail(filename,dest,THUMB_MAX);
197 
198     fprintf(stderr,"transform ");
199     jpeg_transform_inplace(filename, JXFORM_NONE, NULL,
200 			   dest, size, JFLAG_UPDATE_THUMBNAIL);
201 
202     fprintf(stderr,"done\n");
203     return 0;
204 }
205 
206 int main(int argc, char *argv[])
207 {
208     int i;
209 
210     for (i = 1; i < argc; i++)
211 	handle_image(argv[i]);
212     return 0;
213 }
214 
215 #endif
216 
217