Coverage Report

Created: 2026-02-14 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
};