1 /*
2  * tumble: build a PDF file from image files
3  *
4  * Copyright 2003, 2017 Eric Smith <spacewar@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.  Note that permission is
9  * not granted to redistribute this program under the terms of any
10  * other version of the General Public License.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20  *
21  *  2009-03-02 [JDB] Add support for overlay images.
22  */
23 
24 
25 #include <stdbool.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <strings.h>  /* strcasecmp() is a BSDism */
29 #include <jpeglib.h>
30 
31 
32 #include "semantics.h"
33 #include "tumble.h"
34 #include "bitblt.h"
35 #include "pdf.h"
36 #include "tumble_input.h"
37 
38 
39 static FILE *jpeg_f;
40 
41 static struct jpeg_decompress_struct cinfo;
42 static struct jpeg_error_mgr jerr;
43 
44 
match_jpeg_suffix(char * suffix)45 static bool match_jpeg_suffix (char *suffix)
46 {
47   return ((strcasecmp (suffix, ".jpg") == 0) ||
48 	  (strcasecmp (suffix, ".jpeg") == 0));
49 }
50 
close_jpeg_input_file(void)51 static bool close_jpeg_input_file (void)
52 {
53   return (1);
54 }
55 
56 
open_jpeg_input_file(FILE * f,char * name)57 static bool open_jpeg_input_file (FILE *f, char *name)
58 {
59   uint8_t buf [2];
60   size_t l;
61 
62   l = fread (& buf [0], 1, sizeof (buf), f);
63   if (l != sizeof (buf))
64     return (0);
65 
66   rewind (f);
67 
68   if ((buf [0] != 0xff) || (buf [1] != 0xd8))
69     return (0);
70 
71   cinfo.err = jpeg_std_error (& jerr);
72   jpeg_create_decompress (& cinfo);
73 
74   jpeg_stdio_src (& cinfo, f);
75 
76   jpeg_read_header (& cinfo, TRUE);
77 
78   rewind (f);
79 
80   jpeg_f = f;
81 
82   return (1);
83 }
84 
85 
last_jpeg_input_page(void)86 static bool last_jpeg_input_page (void)
87 {
88   return (1);
89 }
90 
91 
get_jpeg_image_info(int image,input_attributes_t input_attributes,image_info_t * image_info)92 static bool get_jpeg_image_info (int image,
93 				 input_attributes_t input_attributes,
94 				 image_info_t *image_info)
95 {
96   double unit;
97 
98 #ifdef DEBUG_JPEG
99   printf ("color space: %d\n", cinfo.jpeg_color_space);
100   printf ("components: %d\n", cinfo.num_components);
101   printf ("density unit: %d\n", cinfo.density_unit);
102   printf ("x density: %d\n", cinfo.X_density);
103   printf ("y density: %d\n", cinfo.Y_density);
104   printf ("width: %d\n", cinfo.image_width);
105   printf ("height: %d\n", cinfo.image_height);
106 #endif
107 
108   switch (cinfo.jpeg_color_space)
109     {
110     case JCS_GRAYSCALE:
111       if (cinfo.num_components != 1)
112 	{
113 	  fprintf (stderr, "JPEG grayscale image has %d components, should have 1\n",
114 		   cinfo.num_components);
115 	  return (0);
116 	}
117       image_info->color = 0;
118       break;
119     case JCS_RGB:
120     case JCS_YCbCr:
121       if (cinfo.num_components != 3)
122 	{
123 	  fprintf (stderr, "JPEG RGB or YCbCr image has %d components, should have 3\n",
124 		   cinfo.num_components);
125 	  return (0);
126 	}
127       image_info->color = 1;
128       break;
129     default:
130       fprintf (stderr, "JPEG color space %d not supported\n", cinfo.jpeg_color_space);
131       return (0);
132     }
133   image_info->width_samples = cinfo.image_width;
134   image_info->height_samples = cinfo.image_height;
135 
136   if (cinfo.saw_JFIF_marker & cinfo.density_unit)
137     {
138       switch (cinfo.density_unit)
139 	{
140 	case 1:  /* samples per inch */
141 	  unit = 1.0;
142 	  break;
143 	case 2:  /* samples per cm */
144 	  unit = 2.54;
145 	  break;
146 	default:
147 	  fprintf (stderr, "JFIF density unit %d not supported\n", cinfo.density_unit);
148 	  return (0);
149 	}
150       image_info->width_points = ((image_info->width_samples * POINTS_PER_INCH) /
151 				  (cinfo.X_density * unit));
152       image_info->height_points = ((image_info->height_samples * POINTS_PER_INCH) /
153 				   (cinfo.Y_density * unit));
154     }
155   else
156     {
157       /* assume 300 DPI - not great, but what else can we do? */
158       image_info->width_points = (image_info->width_samples * POINTS_PER_INCH) / 300.0;
159       image_info->height_points = (image_info->height_samples * POINTS_PER_INCH) / 300.0;
160     }
161 
162   return (1);
163 }
164 
165 
process_jpeg_image(int image,input_attributes_t input_attributes,image_info_t * image_info,pdf_page_handle page,position_t position)166 static bool process_jpeg_image (int image,  /* range 1 .. n */
167 				input_attributes_t input_attributes,
168 				image_info_t *image_info,
169 				pdf_page_handle page,
170 				position_t position)
171 {
172   pdf_write_jpeg_image (page,
173 			position.x, position.y,
174 			image_info->width_points,
175 			image_info->height_points,
176 			image_info->color,
177 			image_info->width_samples,
178 			image_info->height_samples,
179 			input_attributes.transparency,
180 			jpeg_f);
181 
182   return (1);
183 }
184 
185 
186 input_handler_t jpeg_handler =
187   {
188     match_jpeg_suffix,
189     open_jpeg_input_file,
190     close_jpeg_input_file,
191     last_jpeg_input_page,
192     get_jpeg_image_info,
193     process_jpeg_image
194   };
195 
196 
init_jpeg_handler(void)197 void init_jpeg_handler (void)
198 {
199   install_input_handler (& jpeg_handler);
200 }
201