Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7639 views
1
#include "mupdf/fitz.h"
2
3
#define DPI 72.0f
4
5
typedef struct cbz_document_s cbz_document;
6
typedef struct cbz_page_s cbz_page;
7
8
static const char *cbz_ext_list[] = {
9
".jpg", ".jpeg", ".png",
10
".JPG", ".JPEG", ".PNG",
11
NULL
12
};
13
14
struct cbz_page_s
15
{
16
fz_page super;
17
fz_image *image;
18
};
19
20
struct cbz_document_s
21
{
22
fz_document super;
23
fz_archive *zip;
24
int page_count;
25
const char **page;
26
};
27
28
static inline int cbz_isdigit(int c)
29
{
30
return c >= '0' && c <= '9';
31
}
32
33
static inline int cbz_toupper(int c)
34
{
35
if (c >= 'a' && c <= 'z')
36
return c - 'a' + 'A';
37
return c;
38
}
39
40
static inline int
41
cbz_strnatcmp(const char *a, const char *b)
42
{
43
int x, y;
44
45
while (*a || *b)
46
{
47
if (cbz_isdigit(*a) && cbz_isdigit(*b))
48
{
49
x = *a++ - '0';
50
while (cbz_isdigit(*a))
51
x = x * 10 + *a++ - '0';
52
y = *b++ - '0';
53
while (cbz_isdigit(*b))
54
y = y * 10 + *b++ - '0';
55
}
56
else
57
{
58
x = cbz_toupper(*a++);
59
y = cbz_toupper(*b++);
60
}
61
if (x < y)
62
return -1;
63
if (x > y)
64
return 1;
65
}
66
67
return 0;
68
}
69
70
static int
71
cbz_compare_page_names(const void *a, const void *b)
72
{
73
return cbz_strnatcmp(*(const char **)a, *(const char **)b);
74
}
75
76
static void
77
cbz_create_page_list(fz_context *ctx, cbz_document *doc)
78
{
79
fz_archive *zip = doc->zip;
80
int i, k, count;
81
82
count = fz_count_archive_entries(ctx, zip);
83
84
doc->page_count = 0;
85
doc->page = fz_malloc_array(ctx, count, sizeof *doc->page);
86
87
for (i = 0; i < count; i++)
88
{
89
for (k = 0; cbz_ext_list[k]; k++)
90
{
91
const char *name = fz_list_archive_entry(ctx, zip, i);
92
if (strstr(name, cbz_ext_list[k]))
93
{
94
doc->page[doc->page_count++] = name;
95
break;
96
}
97
}
98
}
99
100
qsort((char **)doc->page, doc->page_count, sizeof *doc->page, cbz_compare_page_names);
101
}
102
103
static void
104
cbz_close_document(fz_context *ctx, cbz_document *doc)
105
{
106
fz_drop_archive(ctx, doc->zip);
107
fz_free(ctx, (char **)doc->page);
108
fz_free(ctx, doc);
109
}
110
111
static int
112
cbz_count_pages(fz_context *ctx, cbz_document *doc)
113
{
114
return doc->page_count;
115
}
116
117
static fz_rect *
118
cbz_bound_page(fz_context *ctx, cbz_page *page, fz_rect *bbox)
119
{
120
fz_image *image = page->image;
121
int xres, yres;
122
123
fz_image_get_sanitised_res(image, &xres, &yres);
124
bbox->x0 = bbox->y0 = 0;
125
bbox->x1 = image->w * DPI / xres;
126
bbox->y1 = image->h * DPI / yres;
127
return bbox;
128
}
129
130
static void
131
cbz_run_page(fz_context *ctx, cbz_page *page, fz_device *dev, const fz_matrix *ctm, fz_cookie *cookie)
132
{
133
fz_matrix local_ctm = *ctm;
134
fz_image *image = page->image;
135
int xres, yres;
136
float w, h;
137
138
fz_image_get_sanitised_res(image, &xres, &yres);
139
w = image->w * DPI / xres;
140
h = image->h * DPI / yres;
141
fz_pre_scale(&local_ctm, w, h);
142
fz_fill_image(ctx, dev, image, &local_ctm, 1);
143
}
144
145
static void
146
cbz_drop_page_imp(fz_context *ctx, cbz_page *page)
147
{
148
if (!page)
149
return;
150
fz_drop_image(ctx, page->image);
151
}
152
153
static cbz_page *
154
cbz_load_page(fz_context *ctx, cbz_document *doc, int number)
155
{
156
unsigned char *data = NULL;
157
cbz_page *page = NULL;
158
fz_buffer *buf;
159
160
if (number < 0 || number >= doc->page_count)
161
return NULL;
162
163
fz_var(data);
164
fz_var(page);
165
166
buf = fz_read_archive_entry(ctx, doc->zip, doc->page[number]);
167
fz_try(ctx)
168
{
169
page = fz_new_page(ctx, sizeof *page);
170
page->super.bound_page = (fz_page_bound_page_fn *)cbz_bound_page;
171
page->super.run_page_contents = (fz_page_run_page_contents_fn *)cbz_run_page;
172
page->super.drop_page_imp = (fz_page_drop_page_imp_fn *)cbz_drop_page_imp;
173
page->image = fz_new_image_from_buffer(ctx, buf);
174
}
175
fz_always(ctx)
176
{
177
fz_drop_buffer(ctx, buf);
178
}
179
fz_catch(ctx)
180
{
181
fz_free(ctx, data);
182
cbz_drop_page_imp(ctx, page);
183
fz_rethrow(ctx);
184
}
185
186
return page;
187
}
188
189
static int
190
cbz_lookup_metadata(fz_context *ctx, cbz_document *doc, const char *key, char *buf, int size)
191
{
192
if (!strcmp(key, "format"))
193
return fz_strlcpy(buf, "CBZ", size);
194
return -1;
195
}
196
197
static cbz_document *
198
cbz_open_document_with_stream(fz_context *ctx, fz_stream *file)
199
{
200
cbz_document *doc = fz_new_document(ctx, sizeof *doc);
201
202
doc->super.close = (fz_document_close_fn *)cbz_close_document;
203
doc->super.count_pages = (fz_document_count_pages_fn *)cbz_count_pages;
204
doc->super.load_page = (fz_document_load_page_fn *)cbz_load_page;
205
doc->super.lookup_metadata = (fz_document_lookup_metadata_fn *)cbz_lookup_metadata;
206
207
fz_try(ctx)
208
{
209
doc->zip = fz_open_archive_with_stream(ctx, file);
210
cbz_create_page_list(ctx, doc);
211
}
212
fz_catch(ctx)
213
{
214
cbz_close_document(ctx, doc);
215
fz_rethrow(ctx);
216
}
217
return doc;
218
}
219
220
static cbz_document *
221
cbz_open_document(fz_context *ctx, const char *filename)
222
{
223
fz_stream *file;
224
cbz_document *doc;
225
226
file = fz_open_file(ctx, filename);
227
228
fz_try(ctx)
229
doc = cbz_open_document_with_stream(ctx, file);
230
fz_always(ctx)
231
fz_drop_stream(ctx, file);
232
fz_catch(ctx)
233
fz_rethrow(ctx);
234
235
return doc;
236
}
237
238
static int
239
cbz_recognize(fz_context *doc, const char *magic)
240
{
241
char *ext = strrchr(magic, '.');
242
243
if (ext)
244
{
245
if (!fz_strcasecmp(ext, ".cbz") || !fz_strcasecmp(ext, ".zip"))
246
return 100;
247
}
248
if (!strcmp(magic, "cbz") || !strcmp(magic, "application/x-cbz"))
249
return 100;
250
251
return 0;
252
}
253
254
fz_document_handler cbz_document_handler =
255
{
256
(fz_document_recognize_fn *)&cbz_recognize,
257
(fz_document_open_fn *)&cbz_open_document,
258
(fz_document_open_with_stream_fn *)&cbz_open_document_with_stream
259
};
260
261