1 /*
2 * tumble: build a PDF file from image files
3 *
4 * PDF routines
5 * Copyright 2003, 2017 Eric Smith <spacewar@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation. Note that permission is
10 * not granted to redistribute this program under the terms of any
11 * other version of the General Public License.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
21 *
22 * 2008-12-30 [JDB] Fixed bug wherein "pdf_write_g4_content_callback" called
23 * "pdf_stream_printf" to write XObject name without escaping
24 * restricted characters. Now calls "pdf_write_name".
25 *
26 * 2010-09-02 [JDB] Added support for min-is-black TIFF images.
27 */
28
29
30 #include <stdbool.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36
37 #include "bitblt.h"
38 #include "pdf.h"
39 #include "pdf_util.h"
40 #include "pdf_prim.h"
41 #include "pdf_private.h"
42
43
44 struct pdf_g4_image
45 {
46 double width, height;
47 double x, y;
48 unsigned long Columns;
49 unsigned long Rows;
50 Bitmap *bitmap;
51 char XObject_name [4];
52 };
53
54
pdf_write_g4_content_callback(pdf_file_handle pdf_file,struct pdf_obj * stream,void * app_data)55 static void pdf_write_g4_content_callback (pdf_file_handle pdf_file,
56 struct pdf_obj *stream,
57 void *app_data)
58 {
59 struct pdf_g4_image *image = app_data;
60
61 /* transformation matrix is: width 0 0 height x y cm */
62 pdf_stream_printf (pdf_file, stream, "q %g 0 0 %g %g %g cm ",
63 image->width, image->height,
64 image->x, image->y);
65
66 pdf_write_name (pdf_file, image->XObject_name);
67 pdf_stream_printf (pdf_file, stream, "Do Q\r\n");
68 }
69
70
pdf_write_g4_fax_image_callback(pdf_file_handle pdf_file,struct pdf_obj * stream,void * app_data)71 static void pdf_write_g4_fax_image_callback (pdf_file_handle pdf_file,
72 struct pdf_obj *stream,
73 void *app_data)
74 {
75 struct pdf_g4_image *image = app_data;
76
77 bitblt_write_g4 (image->bitmap, pdf_file->f);
78 }
79
80
pdf_write_g4_fax_image(pdf_page_handle pdf_page,double x,double y,double width,double height,bool negative,Bitmap * bitmap,colormap_t * colormap,rgb_range_t * transparency)81 void pdf_write_g4_fax_image (pdf_page_handle pdf_page,
82 double x,
83 double y,
84 double width,
85 double height,
86 bool negative,
87 Bitmap *bitmap,
88 colormap_t *colormap,
89 rgb_range_t *transparency)
90 {
91 struct pdf_g4_image *image;
92
93 struct pdf_obj *stream;
94 struct pdf_obj *stream_dict;
95 struct pdf_obj *decode_parms;
96
97 struct pdf_obj *content_stream;
98
99 struct pdf_obj *contents;
100 struct pdf_obj *mask;
101
102 typedef char MAP_STRING[6];
103
104 MAP_STRING color_index;
105 static MAP_STRING last_color_index;
106 static struct pdf_obj *color_space;
107
108
109 pdf_add_array_elem_unique (pdf_page->procset, pdf_new_name ("ImageB"));
110
111 image = pdf_calloc (1, sizeof (struct pdf_g4_image));
112
113 image->width = width;
114 image->height = height;
115 image->x = x;
116 image->y = y;
117
118 image->bitmap = bitmap;
119 image->Columns = bitmap->rect.max.x - bitmap->rect.min.x;
120 image->Rows = bitmap->rect.max.y - bitmap->rect.min.y;
121
122 stream_dict = pdf_new_obj (PT_DICTIONARY);
123
124 stream = pdf_new_ind_ref (pdf_page->pdf_file,
125 pdf_new_stream (pdf_page->pdf_file,
126 stream_dict,
127 & pdf_write_g4_fax_image_callback,
128 image));
129
130 strcpy (& image->XObject_name [0], "Im ");
131 image->XObject_name [2] = pdf_new_XObject (pdf_page, stream);
132
133 pdf_set_dict_entry (stream_dict, "Type", pdf_new_name ("XObject"));
134 pdf_set_dict_entry (stream_dict, "Subtype", pdf_new_name ("Image"));
135 pdf_set_dict_entry (stream_dict, "Name", pdf_new_name (& image->XObject_name [0]));
136 pdf_set_dict_entry (stream_dict, "Width", pdf_new_integer (image->Columns));
137 pdf_set_dict_entry (stream_dict, "Height", pdf_new_integer (image->Rows));
138 pdf_set_dict_entry (stream_dict, "BitsPerComponent", pdf_new_integer (1));
139
140 if (transparency)
141 {
142 mask = pdf_new_obj (PT_ARRAY);
143
144 pdf_add_array_elem (mask, pdf_new_integer (transparency->red.first));
145 pdf_add_array_elem (mask, pdf_new_integer (transparency->red.last));
146
147 pdf_set_dict_entry (stream_dict, "Mask", mask);
148 }
149
150 if (colormap)
151 {
152 color_index [0] = (char) colormap->black_map.red;
153 color_index [1] = (char) colormap->black_map.green;
154 color_index [2] = (char) colormap->black_map.blue;
155 color_index [3] = (char) colormap->white_map.red;
156 color_index [4] = (char) colormap->white_map.green;
157 color_index [5] = (char) colormap->white_map.blue;
158
159 if ((color_space == NULL) ||
160 (memcmp (color_index, last_color_index, sizeof (MAP_STRING)) != 0))
161 {
162 memcpy (last_color_index, color_index, sizeof (MAP_STRING));
163
164 color_space = pdf_new_obj (PT_ARRAY);
165 pdf_add_array_elem (color_space, pdf_new_name ("Indexed"));
166 pdf_add_array_elem (color_space, pdf_new_name ("DeviceRGB"));
167 pdf_add_array_elem (color_space, pdf_new_integer (1));
168 pdf_add_array_elem (color_space, pdf_new_string_n (color_index, 6));
169
170 color_space = pdf_new_ind_ref (pdf_page->pdf_file, color_space);
171 }
172
173 pdf_set_dict_entry (stream_dict, "ColorSpace", color_space);
174 }
175 else
176 pdf_set_dict_entry (stream_dict, "ColorSpace", pdf_new_name ("DeviceGray"));
177
178 decode_parms = pdf_new_obj (PT_DICTIONARY);
179
180 pdf_set_dict_entry (decode_parms,
181 "K",
182 pdf_new_integer (-1));
183
184 pdf_set_dict_entry (decode_parms,
185 "Columns",
186 pdf_new_integer (image->Columns));
187
188 pdf_set_dict_entry (decode_parms,
189 "Rows",
190 pdf_new_integer (image->Rows));
191
192 if (negative)
193 pdf_set_dict_entry (decode_parms,
194 "BlackIs1",
195 pdf_new_bool (true));
196
197 pdf_stream_add_filter (stream, "CCITTFaxDecode", decode_parms);
198
199 /* the following will write the stream, using our callback function to
200 get the actual data */
201 pdf_write_ind_obj (pdf_page->pdf_file, stream);
202
203 content_stream = pdf_new_ind_ref (pdf_page->pdf_file,
204 pdf_new_stream (pdf_page->pdf_file,
205 pdf_new_obj (PT_DICTIONARY),
206 & pdf_write_g4_content_callback,
207 image));
208
209 contents = pdf_get_dict_entry (pdf_page->page_dict, "Contents");
210
211 if (! contents)
212 contents = pdf_new_obj (PT_ARRAY);
213
214 pdf_add_array_elem (contents, content_stream);
215 pdf_set_dict_entry (pdf_page->page_dict, "Contents", contents);
216
217 pdf_write_ind_obj (pdf_page->pdf_file, content_stream);
218 }
219
220