/src/freeimage-svn/FreeImage/trunk/Source/LibRawLite/src/utils/thumb_utils.cpp
Line | Count | Source |
1 | | /* -*- C++ -*- |
2 | | * Copyright 2019-2021 LibRaw LLC (info@libraw.org) |
3 | | * |
4 | | |
5 | | LibRaw is free software; you can redistribute it and/or modify |
6 | | it under the terms of the one of two licenses as you choose: |
7 | | |
8 | | 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 |
9 | | (See file LICENSE.LGPL provided in LibRaw distribution archive for details). |
10 | | |
11 | | 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 |
12 | | (See file LICENSE.CDDL provided in LibRaw distribution archive for details). |
13 | | |
14 | | */ |
15 | | |
16 | | #include "../../internal/libraw_cxx_defs.h" |
17 | | |
18 | | void LibRaw::kodak_thumb_loader() |
19 | 0 | { |
20 | 0 | INT64 est_datasize = |
21 | 0 | T.theight * T.twidth / 3; // is 0.3 bytes per pixel good estimate? |
22 | 0 | if (ID.toffset < 0) |
23 | 0 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
24 | | |
25 | 0 | if (ID.toffset + est_datasize > ID.input->size() + THUMB_READ_BEYOND) |
26 | 0 | throw LIBRAW_EXCEPTION_IO_EOF; |
27 | | |
28 | 0 | if(INT64(T.theight) * INT64(T.twidth) > 1024ULL * 1024ULL * LIBRAW_MAX_THUMBNAIL_MB) |
29 | 0 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
30 | | |
31 | 0 | if (INT64(T.theight) * INT64(T.twidth) < 64ULL) |
32 | 0 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
33 | | |
34 | 0 | if(T.twidth < 16 || T.twidth > 8192 || T.theight < 16 || T.theight > 8192) |
35 | 0 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
36 | | |
37 | | // some kodak cameras |
38 | 0 | ushort s_height = S.height, s_width = S.width, s_iwidth = S.iwidth, |
39 | 0 | s_iheight = S.iheight; |
40 | 0 | ushort s_flags = libraw_internal_data.unpacker_data.load_flags; |
41 | 0 | libraw_internal_data.unpacker_data.load_flags = 12; |
42 | 0 | int s_colors = P1.colors; |
43 | 0 | unsigned s_filters = P1.filters; |
44 | 0 | ushort(*s_image)[4] = imgdata.image; |
45 | |
|
46 | 0 | S.height = T.theight; |
47 | 0 | S.width = T.twidth; |
48 | 0 | P1.filters = 0; |
49 | |
|
50 | 0 | #define Tformat libraw_internal_data.unpacker_data.thumb_format |
51 | | |
52 | |
|
53 | 0 | if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_KODAK_YCBCR) |
54 | 0 | { |
55 | 0 | S.height += S.height & 1; |
56 | 0 | S.width += S.width & 1; |
57 | 0 | } |
58 | |
|
59 | 0 | S.iheight = S.height; |
60 | 0 | S.iwidth = S.width; |
61 | |
|
62 | 0 | imgdata.image = |
63 | 0 | (ushort(*)[4])calloc(S.iheight * S.iwidth, sizeof(*imgdata.image)); |
64 | |
|
65 | 0 | ID.input->seek(ID.toffset, SEEK_SET); |
66 | | // read kodak thumbnail into T.image[] |
67 | 0 | try |
68 | 0 | { |
69 | 0 | if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_KODAK_YCBCR) |
70 | 0 | kodak_ycbcr_load_raw(); |
71 | 0 | else if(Tformat == LIBRAW_INTERNAL_THUMBNAIL_KODAK_RGB) |
72 | 0 | kodak_rgb_load_raw(); |
73 | 0 | else if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_KODAK_THUMB) |
74 | 0 | kodak_thumb_load_raw(); |
75 | 0 | } |
76 | 0 | catch (...) |
77 | 0 | { |
78 | 0 | free(imgdata.image); |
79 | 0 | imgdata.image = s_image; |
80 | |
|
81 | 0 | T.twidth = 0; |
82 | 0 | S.width = s_width; |
83 | |
|
84 | 0 | S.iwidth = s_iwidth; |
85 | 0 | S.iheight = s_iheight; |
86 | |
|
87 | 0 | T.theight = 0; |
88 | 0 | S.height = s_height; |
89 | |
|
90 | 0 | T.tcolors = 0; |
91 | 0 | P1.colors = s_colors; |
92 | |
|
93 | 0 | P1.filters = s_filters; |
94 | 0 | T.tlength = 0; |
95 | 0 | libraw_internal_data.unpacker_data.load_flags = s_flags; |
96 | 0 | return; |
97 | 0 | } |
98 | | |
99 | | // from scale_colors |
100 | 0 | { |
101 | 0 | double dmax; |
102 | 0 | float scale_mul[4]; |
103 | 0 | int c, val; |
104 | 0 | for (dmax = DBL_MAX, c = 0; c < 3; c++) |
105 | 0 | if (dmax > C.pre_mul[c]) |
106 | 0 | dmax = C.pre_mul[c]; |
107 | |
|
108 | 0 | for (c = 0; c < 3; c++) |
109 | 0 | scale_mul[c] = (C.pre_mul[c] / dmax) * 65535.0 / C.maximum; |
110 | 0 | scale_mul[3] = scale_mul[1]; |
111 | |
|
112 | 0 | size_t size = S.height * S.width; |
113 | 0 | for (unsigned i = 0; i < size * 4; i++) |
114 | 0 | { |
115 | 0 | val = imgdata.image[0][i]; |
116 | 0 | if (!val) |
117 | 0 | continue; |
118 | 0 | val *= scale_mul[i & 3]; |
119 | 0 | imgdata.image[0][i] = CLIP(val); |
120 | 0 | } |
121 | 0 | } |
122 | | |
123 | | // from convert_to_rgb |
124 | 0 | ushort *img; |
125 | 0 | int row, col; |
126 | |
|
127 | 0 | int(*t_hist)[LIBRAW_HISTOGRAM_SIZE] = |
128 | 0 | (int(*)[LIBRAW_HISTOGRAM_SIZE])calloc(sizeof(*t_hist), 4); |
129 | |
|
130 | 0 | float out[3], out_cam[3][4] = {{2.81761312f, -1.98369181f, 0.166078627f, 0}, |
131 | 0 | {-0.111855984f, 1.73688626f, -0.625030339f, 0}, |
132 | 0 | {-0.0379119813f, -0.891268849f, 1.92918086f, 0}}; |
133 | |
|
134 | 0 | for (img = imgdata.image[0], row = 0; row < S.height; row++) |
135 | 0 | for (col = 0; col < S.width; col++, img += 4) |
136 | 0 | { |
137 | 0 | out[0] = out[1] = out[2] = 0; |
138 | 0 | int c; |
139 | 0 | for (c = 0; c < 3; c++) |
140 | 0 | { |
141 | 0 | out[0] += out_cam[0][c] * img[c]; |
142 | 0 | out[1] += out_cam[1][c] * img[c]; |
143 | 0 | out[2] += out_cam[2][c] * img[c]; |
144 | 0 | } |
145 | 0 | for (c = 0; c < 3; c++) |
146 | 0 | img[c] = CLIP((int)out[c]); |
147 | 0 | for (c = 0; c < P1.colors; c++) |
148 | 0 | t_hist[c][img[c] >> 3]++; |
149 | 0 | } |
150 | | |
151 | | // from gamma_lut |
152 | 0 | int(*save_hist)[LIBRAW_HISTOGRAM_SIZE] = |
153 | 0 | libraw_internal_data.output_data.histogram; |
154 | 0 | libraw_internal_data.output_data.histogram = t_hist; |
155 | | |
156 | | // make curve output curve! |
157 | 0 | ushort *t_curve = (ushort *)calloc(sizeof(C.curve), 1); |
158 | 0 | memmove(t_curve, C.curve, sizeof(C.curve)); |
159 | 0 | memset(C.curve, 0, sizeof(C.curve)); |
160 | 0 | { |
161 | 0 | int perc, val, total, t_white = 0x2000, c; |
162 | |
|
163 | 0 | perc = S.width * S.height * 0.01; /* 99th percentile white level */ |
164 | 0 | if (IO.fuji_width) |
165 | 0 | perc /= 2; |
166 | 0 | if (!((O.highlight & ~2) || O.no_auto_bright)) |
167 | 0 | for (t_white = c = 0; c < P1.colors; c++) |
168 | 0 | { |
169 | 0 | for (val = 0x2000, total = 0; --val > 32;) |
170 | 0 | if ((total += libraw_internal_data.output_data.histogram[c][val]) > |
171 | 0 | perc) |
172 | 0 | break; |
173 | 0 | if (t_white < val) |
174 | 0 | t_white = val; |
175 | 0 | } |
176 | 0 | gamma_curve(O.gamm[0], O.gamm[1], 2, (t_white << 3) / O.bright); |
177 | 0 | } |
178 | |
|
179 | 0 | libraw_internal_data.output_data.histogram = save_hist; |
180 | 0 | free(t_hist); |
181 | | |
182 | | // from write_ppm_tiff - copy pixels into bitmap |
183 | |
|
184 | 0 | int s_flip = imgdata.sizes.flip; |
185 | 0 | if (imgdata.rawparams.options & LIBRAW_RAWOPTIONS_NO_ROTATE_FOR_KODAK_THUMBNAILS) |
186 | 0 | imgdata.sizes.flip = 0; |
187 | |
|
188 | 0 | S.iheight = S.height; |
189 | 0 | S.iwidth = S.width; |
190 | 0 | if (S.flip & 4) |
191 | 0 | SWAP(S.height, S.width); |
192 | |
|
193 | 0 | if (T.thumb) |
194 | 0 | free(T.thumb); |
195 | 0 | T.thumb = (char *)calloc(S.width * S.height, P1.colors); |
196 | 0 | T.tlength = S.width * S.height * P1.colors; |
197 | | |
198 | | // from write_tiff_ppm |
199 | 0 | { |
200 | 0 | int soff = flip_index(0, 0); |
201 | 0 | int cstep = flip_index(0, 1) - soff; |
202 | 0 | int rstep = flip_index(1, 0) - flip_index(0, S.width); |
203 | |
|
204 | 0 | for (int rr = 0; rr < S.height; rr++, soff += rstep) |
205 | 0 | { |
206 | 0 | char *ppm = T.thumb + rr * S.width * P1.colors; |
207 | 0 | for (int cc = 0; cc < S.width; cc++, soff += cstep) |
208 | 0 | for (int c = 0; c < P1.colors; c++) |
209 | 0 | ppm[cc * P1.colors + c] = |
210 | 0 | imgdata.color.curve[imgdata.image[soff][c]] >> 8; |
211 | 0 | } |
212 | 0 | } |
213 | |
|
214 | 0 | memmove(C.curve, t_curve, sizeof(C.curve)); |
215 | 0 | free(t_curve); |
216 | | |
217 | | // restore variables |
218 | 0 | free(imgdata.image); |
219 | 0 | imgdata.image = s_image; |
220 | |
|
221 | 0 | if (imgdata.rawparams.options & LIBRAW_RAWOPTIONS_NO_ROTATE_FOR_KODAK_THUMBNAILS) |
222 | 0 | imgdata.sizes.flip = s_flip; |
223 | |
|
224 | 0 | T.twidth = S.width; |
225 | 0 | S.width = s_width; |
226 | |
|
227 | 0 | S.iwidth = s_iwidth; |
228 | 0 | S.iheight = s_iheight; |
229 | |
|
230 | 0 | T.theight = S.height; |
231 | 0 | S.height = s_height; |
232 | |
|
233 | 0 | T.tcolors = P1.colors; |
234 | 0 | P1.colors = s_colors; |
235 | |
|
236 | 0 | P1.filters = s_filters; |
237 | 0 | libraw_internal_data.unpacker_data.load_flags = s_flags; |
238 | 0 | } |
239 | | |
240 | | // ������� thumbnail �� �����, ������ thumb_format � ������������ � �������� |
241 | | |
242 | | int LibRaw::thumbOK(INT64 maxsz) |
243 | 0 | { |
244 | 0 | if (!ID.input) |
245 | 0 | return 0; |
246 | 0 | if (!ID.toffset && !(imgdata.thumbnail.tlength > 0 && |
247 | 0 | load_raw == &LibRaw::broadcom_load_raw) // RPi |
248 | | #ifdef USE_6BY9RPI |
249 | | && !(imgdata.thumbnail.tlength > 0 && libraw_internal_data.unpacker_data.load_flags & 0x4000 && |
250 | | (load_raw == &LibRaw::rpi_load_raw8 || load_raw == &LibRaw::nokia_load_raw || |
251 | | load_raw == &LibRaw::rpi_load_raw12 || load_raw == &LibRaw::rpi_load_raw14)) |
252 | | #endif |
253 | 0 | ) |
254 | 0 | return 0; |
255 | 0 | INT64 fsize = ID.input->size(); |
256 | 0 | if (fsize > 0xffffffffU) |
257 | 0 | return 0; // No thumb for raw > 4Gb-1 |
258 | 0 | int tsize = 0; |
259 | 0 | int tcol = (T.tcolors > 0 && T.tcolors < 4) ? T.tcolors : 3; |
260 | 0 | if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_JPEG) |
261 | 0 | tsize = T.tlength; |
262 | 0 | else if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_PPM) |
263 | 0 | tsize = tcol * T.twidth * T.theight; |
264 | 0 | else if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_PPM16) |
265 | 0 | tsize = tcol * T.twidth * T.theight * |
266 | 0 | ((imgdata.rawparams.options & LIBRAW_RAWOPTIONS_USE_PPM16_THUMBS) ? 2 : 1); |
267 | | #ifdef USE_X3FTOOLS |
268 | | else if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_X3F) |
269 | | { |
270 | | tsize = x3f_thumb_size(); |
271 | | } |
272 | | #endif |
273 | 0 | else // Kodak => no check |
274 | 0 | tsize = 1; |
275 | 0 | if (tsize < 0) |
276 | 0 | return 0; |
277 | 0 | if (maxsz > 0 && tsize > maxsz) |
278 | 0 | return 0; |
279 | 0 | return (tsize + ID.toffset <= fsize) ? 1 : 0; |
280 | 0 | } |
281 | | |
282 | | int LibRaw::dcraw_thumb_writer(const char *fname) |
283 | 0 | { |
284 | | // CHECK_ORDER_LOW(LIBRAW_PROGRESS_THUMB_LOAD); |
285 | |
|
286 | 0 | if (!fname) |
287 | 0 | return ENOENT; |
288 | | |
289 | 0 | FILE *tfp = fopen(fname, "wb"); |
290 | |
|
291 | 0 | if (!tfp) |
292 | 0 | return errno; |
293 | | |
294 | 0 | if (!T.thumb) |
295 | 0 | { |
296 | 0 | fclose(tfp); |
297 | 0 | return LIBRAW_OUT_OF_ORDER_CALL; |
298 | 0 | } |
299 | | |
300 | 0 | try |
301 | 0 | { |
302 | 0 | switch (T.tformat) |
303 | 0 | { |
304 | 0 | case LIBRAW_THUMBNAIL_JPEG: |
305 | 0 | jpeg_thumb_writer(tfp, T.thumb, T.tlength); |
306 | 0 | break; |
307 | 0 | case LIBRAW_THUMBNAIL_BITMAP: |
308 | 0 | fprintf(tfp, "P%d\n%d %d\n255\n", T.tcolors == 1 ? 5 : 6, T.twidth, T.theight); |
309 | 0 | fwrite(T.thumb, 1, T.tlength, tfp); |
310 | 0 | break; |
311 | 0 | default: |
312 | 0 | fclose(tfp); |
313 | 0 | return LIBRAW_UNSUPPORTED_THUMBNAIL; |
314 | 0 | } |
315 | 0 | fclose(tfp); |
316 | 0 | return 0; |
317 | 0 | } |
318 | 0 | catch (const std::bad_alloc&) |
319 | 0 | { |
320 | 0 | fclose(tfp); |
321 | 0 | EXCEPTION_HANDLER(LIBRAW_EXCEPTION_ALLOC); |
322 | 0 | } |
323 | 0 | catch (const LibRaw_exceptions& err) |
324 | 0 | { |
325 | 0 | fclose(tfp); |
326 | 0 | EXCEPTION_HANDLER(err); |
327 | 0 | } |
328 | 0 | } |