1#include "mupdf/fitz.h"
2
3#include <string.h>
4
5#define DPI 72.0f
6
7typedef struct img_document_s img_document;
8typedef struct img_page_s img_page;
9
10struct img_page_s
11{
12 fz_page super;
13 fz_image *image;
14};
15
16struct img_document_s
17{
18 fz_document super;
19 fz_buffer *buffer;
20 const char *format;
21 int page_count;
22 fz_pixmap *(*load_subimage)(fz_context *ctx, const unsigned char *p, size_t total, int subimage);
23};
24
25static void
26img_drop_document(fz_context *ctx, fz_document *doc_)
27{
28 img_document *doc = (img_document*)doc_;
29 fz_drop_buffer(ctx, doc->buffer);
30}
31
32static int
33img_count_pages(fz_context *ctx, fz_document *doc_)
34{
35 img_document *doc = (img_document*)doc_;
36 return doc->page_count;
37}
38
39static fz_rect
40img_bound_page(fz_context *ctx, fz_page *page_)
41{
42 img_page *page = (img_page*)page_;
43 fz_image *image = page->image;
44 int xres, yres;
45 fz_rect bbox;
46
47 fz_image_resolution(image, &xres, &yres);
48 bbox.x0 = bbox.y0 = 0;
49 bbox.x1 = image->w * DPI / xres;
50 bbox.y1 = image->h * DPI / yres;
51 return bbox;
52}
53
54static void
55img_run_page(fz_context *ctx, fz_page *page_, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
56{
57 img_page *page = (img_page*)page_;
58 fz_image *image = page->image;
59 int xres, yres;
60 float w, h;
61
62 fz_image_resolution(image, &xres, &yres);
63 w = image->w * DPI / xres;
64 h = image->h * DPI / yres;
65 ctm = fz_pre_scale(ctm, w, h);
66 fz_fill_image(ctx, dev, image, ctm, 1, fz_default_color_params);
67}
68
69static void
70img_drop_page(fz_context *ctx, fz_page *page_)
71{
72 img_page *page = (img_page*)page_;
73 fz_drop_image(ctx, page->image);
74}
75
76static fz_page *
77img_load_page(fz_context *ctx, fz_document *doc_, int number)
78{
79 img_document *doc = (img_document*)doc_;
80 fz_pixmap *pixmap = NULL;
81 fz_image *image = NULL;
82 img_page *page = NULL;
83
84 if (number < 0 || number >= doc->page_count)
85 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot load page %d", number);
86
87 fz_var(pixmap);
88 fz_var(image);
89 fz_var(page);
90
91 fz_try(ctx)
92 {
93 if (doc->load_subimage)
94 {
95 size_t len;
96 unsigned char *data;
97 len = fz_buffer_storage(ctx, doc->buffer, &data);
98 pixmap = doc->load_subimage(ctx, data, len, number);
99 image = fz_new_image_from_pixmap(ctx, pixmap, NULL);
100 }
101 else
102 {
103 image = fz_new_image_from_buffer(ctx, doc->buffer);
104 }
105
106 page = fz_new_derived_page(ctx, img_page);
107 page->super.bound_page = img_bound_page;
108 page->super.run_page_contents = img_run_page;
109 page->super.drop_page = img_drop_page;
110 page->image = fz_keep_image(ctx, image);
111 }
112 fz_always(ctx)
113 {
114 fz_drop_image(ctx, image);
115 fz_drop_pixmap(ctx, pixmap);
116 }
117 fz_catch(ctx)
118 {
119 fz_free(ctx, page);
120 fz_rethrow(ctx);
121 }
122
123 return (fz_page*)page;
124}
125
126static int
127img_lookup_metadata(fz_context *ctx, fz_document *doc_, const char *key, char *buf, int size)
128{
129 img_document *doc = (img_document*)doc_;
130 if (!strcmp(key, "format"))
131 return (int)fz_strlcpy(buf, doc->format, size);
132 return -1;
133}
134
135static fz_document *
136img_open_document_with_stream(fz_context *ctx, fz_stream *file)
137{
138 img_document *doc = NULL;
139
140 doc = fz_new_derived_document(ctx, img_document);
141
142 doc->super.drop_document = img_drop_document;
143 doc->super.count_pages = img_count_pages;
144 doc->super.load_page = img_load_page;
145 doc->super.lookup_metadata = img_lookup_metadata;
146
147 fz_try(ctx)
148 {
149 int fmt;
150 size_t len;
151 unsigned char *data;
152
153 doc->buffer = fz_read_all(ctx, file, 0);
154 len = fz_buffer_storage(ctx, doc->buffer, &data);
155
156 fmt = FZ_IMAGE_UNKNOWN;
157 if (len >= 8)
158 fmt = fz_recognize_image_format(ctx, data);
159 if (fmt == FZ_IMAGE_TIFF)
160 {
161 doc->page_count = fz_load_tiff_subimage_count(ctx, data, len);
162 doc->load_subimage = fz_load_tiff_subimage;
163 doc->format = "TIFF";
164 }
165 else if (fmt == FZ_IMAGE_PNM)
166 {
167 doc->page_count = fz_load_pnm_subimage_count(ctx, data, len);
168 doc->load_subimage = fz_load_pnm_subimage;
169 doc->format = "PNM";
170 }
171 else if (fmt == FZ_IMAGE_JBIG2)
172 {
173 doc->page_count = fz_load_jbig2_subimage_count(ctx, data, len);
174 doc->load_subimage = fz_load_jbig2_subimage;
175 doc->format = "JBIG2";
176 }
177 else
178 {
179 doc->page_count = 1;
180 doc->format = "Image";
181 }
182 }
183 fz_catch(ctx)
184 {
185 fz_drop_document(ctx, (fz_document*)doc);
186 fz_rethrow(ctx);
187 }
188
189 return (fz_document*)doc;
190}
191
192static const char *img_extensions[] =
193{
194 "bmp",
195 "gif",
196 "hdp",
197 "j2k",
198 "jb2",
199 "jbig2",
200 "jfif",
201 "jfif-tbnl",
202 "jp2",
203 "jpe",
204 "jpeg",
205 "jpg",
206 "jpx",
207 "jxr",
208 "pam",
209 "pbm",
210 "pgm",
211 "pkm",
212 "png",
213 "pnm",
214 "ppm",
215 "tif",
216 "tiff",
217 "wdp",
218 NULL
219};
220
221static const char *img_mimetypes[] =
222{
223 "image/bmp",
224 "image/gif",
225 "image/jp2",
226 "image/jpeg",
227 "image/jpx",
228 "image/jxr",
229 "image/pjpeg",
230 "image/png",
231 "image/tiff",
232 "image/vnd.ms-photo",
233 "image/x-jb2",
234 "image/x-jbig2",
235 "image/x-portable-anymap",
236 "image/x-portable-arbitrarymap",
237 "image/x-portable-bitmap",
238 "image/x-portable-greymap",
239 "image/x-portable-pixmap",
240 "image/x-tiff",
241 NULL
242};
243
244fz_document_handler img_document_handler =
245{
246 NULL,
247 NULL,
248 img_open_document_with_stream,
249 img_extensions,
250 img_mimetypes
251};
252