/src/mupdf/source/cbz/muimg.c
Line | Count | Source |
1 | | // Copyright (C) 2004-2024 Artifex Software, Inc. |
2 | | // |
3 | | // This file is part of MuPDF. |
4 | | // |
5 | | // MuPDF is free software: you can redistribute it and/or modify it under the |
6 | | // terms of the GNU Affero General Public License as published by the Free |
7 | | // Software Foundation, either version 3 of the License, or (at your option) |
8 | | // any later version. |
9 | | // |
10 | | // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY |
11 | | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | | // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
13 | | // details. |
14 | | // |
15 | | // You should have received a copy of the GNU Affero General Public License |
16 | | // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> |
17 | | // |
18 | | // Alternative licensing terms are available from the licensor. |
19 | | // For commercial licensing, see <https://www.artifex.com/> or contact |
20 | | // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
21 | | // CA 94129, USA, for further information. |
22 | | |
23 | | #include "mupdf/fitz.h" |
24 | | |
25 | | #include <string.h> |
26 | | |
27 | 12 | #define DPI 72.0f |
28 | | |
29 | | typedef struct |
30 | | { |
31 | | fz_page super; |
32 | | fz_image *image; |
33 | | } img_page; |
34 | | |
35 | | typedef struct |
36 | | { |
37 | | fz_document super; |
38 | | fz_buffer *buffer; |
39 | | const char *format; |
40 | | int page_count; |
41 | | fz_pixmap *(*load_subimage)(fz_context *ctx, const unsigned char *p, size_t total, int subimage); |
42 | | } img_document; |
43 | | |
44 | | static void |
45 | | img_drop_document(fz_context *ctx, fz_document *doc_) |
46 | 3 | { |
47 | 3 | img_document *doc = (img_document*)doc_; |
48 | 3 | fz_drop_buffer(ctx, doc->buffer); |
49 | 3 | } |
50 | | |
51 | | static int |
52 | | img_count_pages(fz_context *ctx, fz_document *doc_, int chapter) |
53 | 6 | { |
54 | 6 | img_document *doc = (img_document*)doc_; |
55 | 6 | return doc->page_count; |
56 | 6 | } |
57 | | |
58 | | static fz_rect |
59 | | img_bound_page(fz_context *ctx, fz_page *page_, fz_box_type box) |
60 | 3 | { |
61 | 3 | img_page *page = (img_page*)page_; |
62 | 3 | fz_image *image = page->image; |
63 | 3 | int xres, yres; |
64 | 3 | fz_rect bbox; |
65 | 3 | uint8_t orientation = fz_image_orientation(ctx, page->image); |
66 | | |
67 | 3 | fz_image_resolution(image, &xres, &yres); |
68 | 3 | bbox.x0 = bbox.y0 = 0; |
69 | 3 | if (orientation == 0 || (orientation & 1) == 1) |
70 | 3 | { |
71 | 3 | bbox.x1 = image->w * DPI / xres; |
72 | 3 | bbox.y1 = image->h * DPI / yres; |
73 | 3 | } |
74 | 0 | else |
75 | 0 | { |
76 | 0 | bbox.y1 = image->w * DPI / xres; |
77 | 0 | bbox.x1 = image->h * DPI / yres; |
78 | 0 | } |
79 | 3 | return bbox; |
80 | 3 | } |
81 | | |
82 | | static void |
83 | | img_run_page(fz_context *ctx, fz_page *page_, fz_device *dev, fz_matrix ctm, fz_cookie *cookie) |
84 | 3 | { |
85 | 3 | img_page *page = (img_page*)page_; |
86 | 3 | fz_image *image = page->image; |
87 | 3 | int xres, yres; |
88 | 3 | float w, h; |
89 | 3 | uint8_t orientation = fz_image_orientation(ctx, page->image); |
90 | 3 | fz_matrix immat = fz_image_orientation_matrix(ctx, page->image); |
91 | | |
92 | 3 | fz_image_resolution(image, &xres, &yres); |
93 | 3 | if (orientation == 0 || (orientation & 1) == 1) |
94 | 3 | { |
95 | 3 | w = image->w * DPI / xres; |
96 | 3 | h = image->h * DPI / yres; |
97 | 3 | } |
98 | 0 | else |
99 | 0 | { |
100 | 0 | h = image->w * DPI / xres; |
101 | 0 | w = image->h * DPI / yres; |
102 | 0 | } |
103 | 3 | immat = fz_post_scale(immat, w, h); |
104 | 3 | ctm = fz_concat(immat, ctm); |
105 | 3 | fz_fill_image(ctx, dev, image, ctm, 1, fz_default_color_params); |
106 | 3 | } |
107 | | |
108 | | static void |
109 | | img_drop_page(fz_context *ctx, fz_page *page_) |
110 | 3 | { |
111 | 3 | img_page *page = (img_page*)page_; |
112 | 3 | fz_drop_image(ctx, page->image); |
113 | 3 | } |
114 | | |
115 | | static fz_page * |
116 | | img_load_page(fz_context *ctx, fz_document *doc_, int chapter, int number) |
117 | 3 | { |
118 | 3 | img_document *doc = (img_document*)doc_; |
119 | 3 | fz_pixmap *pixmap = NULL; |
120 | 3 | fz_image *image = NULL; |
121 | 3 | img_page *page = NULL; |
122 | | |
123 | 3 | if (number < 0 || number >= doc->page_count) |
124 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "invalid page number %d", number); |
125 | | |
126 | 3 | fz_var(pixmap); |
127 | 3 | fz_var(image); |
128 | 3 | fz_var(page); |
129 | | |
130 | 6 | fz_try(ctx) |
131 | 6 | { |
132 | 3 | if (doc->load_subimage) |
133 | 0 | { |
134 | 0 | size_t len; |
135 | 0 | unsigned char *data; |
136 | 0 | len = fz_buffer_storage(ctx, doc->buffer, &data); |
137 | 0 | pixmap = doc->load_subimage(ctx, data, len, number); |
138 | 0 | image = fz_new_image_from_pixmap(ctx, pixmap, NULL); |
139 | 0 | } |
140 | 3 | else |
141 | 3 | { |
142 | 3 | image = fz_new_image_from_buffer(ctx, doc->buffer); |
143 | 3 | } |
144 | | |
145 | 3 | page = fz_new_derived_page(ctx, img_page, doc_); |
146 | 3 | page->super.bound_page = img_bound_page; |
147 | 3 | page->super.run_page_contents = img_run_page; |
148 | 3 | page->super.drop_page = img_drop_page; |
149 | 3 | page->image = fz_keep_image(ctx, image); |
150 | 3 | } |
151 | 6 | fz_always(ctx) |
152 | 3 | { |
153 | 3 | fz_drop_image(ctx, image); |
154 | 3 | fz_drop_pixmap(ctx, pixmap); |
155 | 3 | } |
156 | 3 | fz_catch(ctx) |
157 | 0 | { |
158 | 0 | fz_free(ctx, page); |
159 | 0 | fz_rethrow(ctx); |
160 | 0 | } |
161 | | |
162 | 3 | return (fz_page*)page; |
163 | 3 | } |
164 | | |
165 | | static int |
166 | | img_lookup_metadata(fz_context *ctx, fz_document *doc_, const char *key, char *buf, size_t size) |
167 | 0 | { |
168 | 0 | img_document *doc = (img_document*)doc_; |
169 | 0 | if (!strcmp(key, FZ_META_FORMAT)) |
170 | 0 | return 1 + (int)fz_strlcpy(buf, doc->format, size); |
171 | 0 | return -1; |
172 | 0 | } |
173 | | |
174 | | static fz_document * |
175 | | img_open_document(fz_context *ctx, const fz_document_handler *handler, fz_stream *file, fz_stream *accel, fz_archive *dir, void *state) |
176 | 3 | { |
177 | 3 | img_document *doc = fz_new_derived_document(ctx, img_document); |
178 | | |
179 | 3 | doc->super.drop_document = img_drop_document; |
180 | 3 | doc->super.count_pages = img_count_pages; |
181 | 3 | doc->super.load_page = img_load_page; |
182 | 3 | doc->super.lookup_metadata = img_lookup_metadata; |
183 | | |
184 | 6 | fz_try(ctx) |
185 | 6 | { |
186 | 3 | int fmt; |
187 | 3 | size_t len; |
188 | 3 | unsigned char *data; |
189 | | |
190 | 3 | doc->buffer = fz_read_all(ctx, file, 0); |
191 | 3 | len = fz_buffer_storage(ctx, doc->buffer, &data); |
192 | | |
193 | 3 | fmt = FZ_IMAGE_UNKNOWN; |
194 | 3 | if (len >= 8) |
195 | 3 | fmt = fz_recognize_image_format(ctx, data); |
196 | 3 | if (fmt == FZ_IMAGE_TIFF) |
197 | 0 | { |
198 | 0 | doc->page_count = fz_load_tiff_subimage_count(ctx, data, len); |
199 | 0 | doc->load_subimage = fz_load_tiff_subimage; |
200 | 0 | doc->format = "TIFF"; |
201 | 0 | } |
202 | 3 | else if (fmt == FZ_IMAGE_PNM) |
203 | 0 | { |
204 | 0 | doc->page_count = fz_load_pnm_subimage_count(ctx, data, len); |
205 | 0 | doc->load_subimage = fz_load_pnm_subimage; |
206 | 0 | doc->format = "PNM"; |
207 | 0 | } |
208 | 3 | else if (fmt == FZ_IMAGE_JBIG2) |
209 | 0 | { |
210 | 0 | doc->page_count = fz_load_jbig2_subimage_count(ctx, data, len); |
211 | 0 | if (doc->page_count > 1) |
212 | 0 | doc->load_subimage = fz_load_jbig2_subimage; |
213 | 0 | doc->format = "JBIG2"; |
214 | 0 | } |
215 | 3 | else if (fmt == FZ_IMAGE_BMP) |
216 | 0 | { |
217 | 0 | doc->page_count = fz_load_bmp_subimage_count(ctx, data, len); |
218 | 0 | doc->load_subimage = fz_load_bmp_subimage; |
219 | 0 | doc->format = "BMP"; |
220 | 0 | } |
221 | 3 | else |
222 | 3 | { |
223 | 3 | doc->page_count = 1; |
224 | 3 | doc->format = "Image"; |
225 | 3 | } |
226 | 3 | } |
227 | 6 | fz_catch(ctx) |
228 | 0 | { |
229 | 0 | fz_drop_document(ctx, (fz_document*)doc); |
230 | 0 | fz_rethrow(ctx); |
231 | 0 | } |
232 | | |
233 | 3 | return (fz_document*)doc; |
234 | 3 | } |
235 | | |
236 | | static int |
237 | | img_recognize_content(fz_context *ctx, const fz_document_handler *handler, fz_stream *stream, fz_archive *dir, void **state, fz_document_recognize_state_free_fn **free_state) |
238 | 21 | { |
239 | 21 | unsigned char data[8]; |
240 | 21 | size_t n; |
241 | 21 | int fmt; |
242 | | |
243 | 21 | if (stream == NULL) |
244 | 0 | return 0; |
245 | | |
246 | 21 | if (state) |
247 | 21 | *state = NULL; |
248 | 21 | if (free_state) |
249 | 21 | *free_state = NULL; |
250 | | |
251 | 21 | n = fz_read(ctx, stream, data, 8); |
252 | | |
253 | 21 | if (n != 8) |
254 | 0 | return 0; |
255 | | |
256 | 21 | fmt = fz_recognize_image_format(ctx, data); |
257 | 21 | if (fmt != FZ_IMAGE_UNKNOWN) |
258 | 3 | return 100; |
259 | | |
260 | 18 | return 0; |
261 | 21 | } |
262 | | |
263 | | static const char *img_extensions[] = |
264 | | { |
265 | | "bmp", |
266 | | "gif", |
267 | | "hdp", |
268 | | "j2k", |
269 | | "jb2", |
270 | | "jbig2", |
271 | | "jfif", |
272 | | "jfif-tbnl", |
273 | | "jp2", |
274 | | "jpe", |
275 | | "jpeg", |
276 | | "jpg", |
277 | | "jpx", |
278 | | "jxr", |
279 | | "pam", |
280 | | "pbm", |
281 | | "pfm", |
282 | | "pgm", |
283 | | "pkm", |
284 | | "png", |
285 | | "pnm", |
286 | | "ppm", |
287 | | "psd", |
288 | | "tif", |
289 | | "tiff", |
290 | | "wdp", |
291 | | NULL |
292 | | }; |
293 | | |
294 | | static const char *img_mimetypes[] = |
295 | | { |
296 | | "image/bmp", |
297 | | "image/gif", |
298 | | "image/jp2", |
299 | | "image/jpeg", |
300 | | "image/jpx", |
301 | | "image/jxr", |
302 | | "image/pjpeg", |
303 | | "image/png", |
304 | | "image/tiff", |
305 | | "image/vnd.ms-photo", |
306 | | "image/vnd.adobe.photoshop", |
307 | | "image/x-jb2", |
308 | | "image/x-jbig2", |
309 | | "image/x-portable-anymap", |
310 | | "image/x-portable-arbitrarymap", |
311 | | "image/x-portable-bitmap", |
312 | | "image/x-portable-greymap", |
313 | | "image/x-portable-pixmap", |
314 | | "image/x-portable-floatmap", |
315 | | "image/x-tiff", |
316 | | NULL |
317 | | }; |
318 | | |
319 | | fz_document_handler img_document_handler = |
320 | | { |
321 | | NULL, |
322 | | img_open_document, |
323 | | img_extensions, |
324 | | img_mimetypes, |
325 | | img_recognize_content |
326 | | }; |