/src/libraw/src/postprocessing/mem_image.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- C++ -*- |
2 | | * Copyright 2019-2024 LibRaw LLC (info@libraw.org) |
3 | | * |
4 | | LibRaw is free software; you can redistribute it and/or modify |
5 | | it under the terms of the one of two licenses as you choose: |
6 | | |
7 | | 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 |
8 | | (See file LICENSE.LGPL provided in LibRaw distribution archive for details). |
9 | | |
10 | | 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 |
11 | | (See file LICENSE.CDDL provided in LibRaw distribution archive for details). |
12 | | |
13 | | */ |
14 | | |
15 | | #include "../../internal/libraw_cxx_defs.h" |
16 | | |
17 | | libraw_processed_image_t *LibRaw::dcraw_make_mem_thumb(int *errcode) |
18 | 0 | { |
19 | 0 | if (!T.thumb) |
20 | 0 | { |
21 | 0 | if (!ID.toffset && !(imgdata.thumbnail.tlength > 0 && |
22 | 0 | load_raw == &LibRaw::broadcom_load_raw) // RPi |
23 | 0 | ) |
24 | 0 | { |
25 | 0 | if (errcode) |
26 | 0 | *errcode = LIBRAW_NO_THUMBNAIL; |
27 | 0 | } |
28 | 0 | else |
29 | 0 | { |
30 | 0 | if (errcode) |
31 | 0 | *errcode = LIBRAW_OUT_OF_ORDER_CALL; |
32 | 0 | } |
33 | 0 | return NULL; |
34 | 0 | } |
35 | | |
36 | 0 | if (T.tlength < 64u) |
37 | 0 | { |
38 | 0 | if (errcode) |
39 | 0 | *errcode = EINVAL; |
40 | 0 | return NULL; |
41 | 0 | } |
42 | | |
43 | 0 | if (INT64(T.tlength) > 1024ULL * 1024ULL * LIBRAW_MAX_THUMBNAIL_MB) |
44 | 0 | { |
45 | 0 | if (errcode) |
46 | 0 | *errcode = LIBRAW_TOO_BIG; |
47 | 0 | return NULL; |
48 | 0 | } |
49 | | |
50 | 0 | if (T.tformat == LIBRAW_THUMBNAIL_BITMAP) |
51 | 0 | { |
52 | 0 | libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc( |
53 | 0 | sizeof(libraw_processed_image_t) + T.tlength); |
54 | |
|
55 | 0 | if (!ret) |
56 | 0 | { |
57 | 0 | if (errcode) |
58 | 0 | *errcode = ENOMEM; |
59 | 0 | return NULL; |
60 | 0 | } |
61 | | |
62 | 0 | memset(ret, 0, sizeof(libraw_processed_image_t)); |
63 | 0 | ret->type = LIBRAW_IMAGE_BITMAP; |
64 | 0 | ret->height = T.theight; |
65 | 0 | ret->width = T.twidth; |
66 | 0 | if (T.tcolors > 0 && T.tcolors < 4) |
67 | 0 | ret->colors = T.tcolors; |
68 | 0 | else |
69 | 0 | ret->colors = 3; // defaults |
70 | 0 | ret->bits = 8; |
71 | 0 | ret->data_size = T.tlength; |
72 | 0 | memmove(ret->data, T.thumb, T.tlength); |
73 | 0 | if (errcode) |
74 | 0 | *errcode = 0; |
75 | 0 | return ret; |
76 | 0 | } |
77 | 0 | else if (T.tformat == LIBRAW_THUMBNAIL_JPEG) |
78 | 0 | { |
79 | 0 | ushort exif[5]; |
80 | 0 | int mk_exif = 0; |
81 | 0 | if (strcmp(T.thumb + 6, "Exif")) |
82 | 0 | mk_exif = 1; |
83 | |
|
84 | 0 | int dsize = T.tlength + mk_exif * (sizeof(exif) + sizeof(tiff_hdr)); |
85 | |
|
86 | 0 | libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc( |
87 | 0 | sizeof(libraw_processed_image_t) + dsize); |
88 | |
|
89 | 0 | if (!ret) |
90 | 0 | { |
91 | 0 | if (errcode) |
92 | 0 | *errcode = ENOMEM; |
93 | 0 | return NULL; |
94 | 0 | } |
95 | | |
96 | 0 | memset(ret, 0, sizeof(libraw_processed_image_t)); |
97 | |
|
98 | 0 | ret->type = LIBRAW_IMAGE_JPEG; |
99 | 0 | ret->data_size = dsize; |
100 | |
|
101 | 0 | ret->data[0] = 0xff; |
102 | 0 | ret->data[1] = 0xd8; |
103 | 0 | if (mk_exif) |
104 | 0 | { |
105 | 0 | struct tiff_hdr th; |
106 | 0 | memcpy(exif, "\xff\xe1 Exif\0\0", 10); |
107 | 0 | exif[1] = htons(8 + sizeof th); |
108 | 0 | memmove(ret->data + 2, exif, sizeof(exif)); |
109 | 0 | tiff_head(&th, 0); |
110 | 0 | memmove(ret->data + (2 + sizeof(exif)), &th, sizeof(th)); |
111 | 0 | memmove(ret->data + (2 + sizeof(exif) + sizeof(th)), T.thumb + 2, |
112 | 0 | T.tlength - 2); |
113 | 0 | } |
114 | 0 | else |
115 | 0 | { |
116 | 0 | memmove(ret->data + 2, T.thumb + 2, T.tlength - 2); |
117 | 0 | } |
118 | 0 | if (errcode) |
119 | 0 | *errcode = 0; |
120 | 0 | return ret; |
121 | 0 | } |
122 | 0 | else if (T.tformat == LIBRAW_THUMBNAIL_H265 || T.tformat == LIBRAW_THUMBNAIL_JPEGXL) |
123 | 0 | { |
124 | 0 | int dsize = T.tlength; |
125 | 0 | libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc(sizeof(libraw_processed_image_t) + dsize); |
126 | 0 | if (!ret) |
127 | 0 | { |
128 | 0 | if (errcode) |
129 | 0 | *errcode = ENOMEM; |
130 | 0 | return NULL; |
131 | 0 | } |
132 | 0 | memset(ret, 0, sizeof(libraw_processed_image_t)); |
133 | 0 | ret->type = T.tformat == LIBRAW_THUMBNAIL_H265 ? LIBRAW_IMAGE_H265 : LIBRAW_IMAGE_JPEGXL; |
134 | 0 | ret->data_size = dsize; |
135 | 0 | memmove(ret->data, T.thumb, dsize); |
136 | 0 | if (errcode) |
137 | 0 | *errcode = 0; |
138 | 0 | return ret; |
139 | 0 | } |
140 | 0 | else |
141 | 0 | { |
142 | 0 | if (errcode) |
143 | 0 | *errcode = LIBRAW_UNSUPPORTED_THUMBNAIL; |
144 | 0 | return NULL; |
145 | 0 | } |
146 | 0 | } |
147 | | |
148 | | // jlb |
149 | | // macros for copying pixels to either BGR or RGB formats |
150 | 0 | #define FORBGR for (c = P1.colors - 1; c >= 0; c--) |
151 | 0 | #define FORRGB for (c = 0; c < P1.colors; c++) |
152 | | |
153 | | void LibRaw::get_mem_image_format(int *width, int *height, int *colors, |
154 | | int *bps) const |
155 | | |
156 | 0 | { |
157 | 0 | *width = S.width; |
158 | 0 | *height = S.height; |
159 | 0 | if (imgdata.progress_flags < LIBRAW_PROGRESS_FUJI_ROTATE) |
160 | 0 | { |
161 | 0 | if (O.use_fuji_rotate) |
162 | 0 | { |
163 | 0 | if (IO.fuji_width) |
164 | 0 | { |
165 | 0 | int fuji_width = (IO.fuji_width - 1 + IO.shrink) >> IO.shrink; |
166 | 0 | *width = (ushort)(fuji_width / sqrt(0.5)); |
167 | 0 | *height = (ushort)((*height - fuji_width) / sqrt(0.5)); |
168 | 0 | } |
169 | 0 | else |
170 | 0 | { |
171 | 0 | if (S.pixel_aspect < 0.995) |
172 | 0 | *height = (ushort)(*height / S.pixel_aspect + 0.5); |
173 | 0 | if (S.pixel_aspect > 1.005) |
174 | 0 | *width = (ushort)(*width * S.pixel_aspect + 0.5); |
175 | 0 | } |
176 | 0 | } |
177 | 0 | } |
178 | 0 | if (S.flip & 4) |
179 | 0 | { |
180 | 0 | std::swap(*width, *height); |
181 | 0 | } |
182 | 0 | *colors = P1.colors; |
183 | 0 | *bps = O.output_bps; |
184 | 0 | } |
185 | | |
186 | | int LibRaw::copy_mem_image(void *scan0, int stride, int bgr) |
187 | | |
188 | 0 | { |
189 | | // the image memory pointed to by scan0 is assumed to be in the format |
190 | | // returned by get_mem_image_format |
191 | 0 | if ((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) < |
192 | 0 | LIBRAW_PROGRESS_PRE_INTERPOLATE) |
193 | 0 | return LIBRAW_OUT_OF_ORDER_CALL; |
194 | | |
195 | 0 | if (libraw_internal_data.output_data.histogram) |
196 | 0 | { |
197 | 0 | int perc, val, total, t_white = 0x2000, c; |
198 | 0 | perc = int(S.width * S.height * O.auto_bright_thr); |
199 | 0 | if (IO.fuji_width) |
200 | 0 | perc /= 2; |
201 | 0 | if (!((O.highlight & ~2) || O.no_auto_bright)) |
202 | 0 | for (t_white = c = 0; c < P1.colors; c++) |
203 | 0 | { |
204 | 0 | for (val = 0x2000, total = 0; --val > 32;) |
205 | 0 | if ((total += libraw_internal_data.output_data.histogram[c][val]) > |
206 | 0 | perc) |
207 | 0 | break; |
208 | 0 | if (t_white < val) |
209 | 0 | t_white = val; |
210 | 0 | } |
211 | 0 | gamma_curve(O.gamm[0], O.gamm[1], 2, int((t_white << 3) / O.bright)); |
212 | 0 | } |
213 | |
|
214 | 0 | int s_iheight = S.iheight; |
215 | 0 | int s_iwidth = S.iwidth; |
216 | 0 | int s_width = S.width; |
217 | 0 | int s_hwight = S.height; |
218 | |
|
219 | 0 | S.iheight = S.height; |
220 | 0 | S.iwidth = S.width; |
221 | |
|
222 | 0 | if (S.flip & 4) |
223 | 0 | SWAP(S.height, S.width); |
224 | 0 | uchar *ppm; |
225 | 0 | ushort *ppm2; |
226 | 0 | int c, row, col, soff, rstep, cstep; |
227 | |
|
228 | 0 | soff = flip_index(0, 0); |
229 | 0 | cstep = flip_index(0, 1) - soff; |
230 | 0 | rstep = flip_index(1, 0) - flip_index(0, S.width); |
231 | |
|
232 | 0 | for (row = 0; row < S.height; row++, soff += rstep) |
233 | 0 | { |
234 | 0 | uchar *bufp = ((uchar *)scan0) + row * stride; |
235 | 0 | ppm2 = (ushort *)(ppm = bufp); |
236 | | // keep trivial decisions in the outer loop for speed |
237 | 0 | if (bgr) |
238 | 0 | { |
239 | 0 | if (O.output_bps == 8) |
240 | 0 | { |
241 | 0 | for (col = 0; col < S.width; col++, soff += cstep) |
242 | 0 | FORBGR *ppm++ = imgdata.color.curve[imgdata.image[soff][c]] >> 8; |
243 | 0 | } |
244 | 0 | else |
245 | 0 | { |
246 | 0 | for (col = 0; col < S.width; col++, soff += cstep) |
247 | 0 | FORBGR *ppm2++ = imgdata.color.curve[imgdata.image[soff][c]]; |
248 | 0 | } |
249 | 0 | } |
250 | 0 | else |
251 | 0 | { |
252 | 0 | if (O.output_bps == 8) |
253 | 0 | { |
254 | 0 | for (col = 0; col < S.width; col++, soff += cstep) |
255 | 0 | FORRGB *ppm++ = imgdata.color.curve[imgdata.image[soff][c]] >> 8; |
256 | 0 | } |
257 | 0 | else |
258 | 0 | { |
259 | 0 | for (col = 0; col < S.width; col++, soff += cstep) |
260 | 0 | FORRGB *ppm2++ = imgdata.color.curve[imgdata.image[soff][c]]; |
261 | 0 | } |
262 | 0 | } |
263 | | |
264 | | // bufp += stride; // go to the next line |
265 | 0 | } |
266 | |
|
267 | 0 | S.iheight = s_iheight; |
268 | 0 | S.iwidth = s_iwidth; |
269 | 0 | S.width = s_width; |
270 | 0 | S.height = s_hwight; |
271 | |
|
272 | 0 | return 0; |
273 | 0 | } |
274 | | #undef FORBGR |
275 | | #undef FORRGB |
276 | | |
277 | | libraw_processed_image_t *LibRaw::dcraw_make_mem_image(int *errcode) |
278 | | |
279 | 0 | { |
280 | 0 | int width, height, colors, bps; |
281 | 0 | get_mem_image_format(&width, &height, &colors, &bps); |
282 | 0 | int stride = width * (bps / 8) * colors; |
283 | 0 | unsigned ds = height * stride; |
284 | 0 | libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc( |
285 | 0 | sizeof(libraw_processed_image_t) + ds); |
286 | 0 | if (!ret) |
287 | 0 | { |
288 | 0 | if (errcode) |
289 | 0 | *errcode = ENOMEM; |
290 | 0 | return NULL; |
291 | 0 | } |
292 | 0 | memset(ret, 0, sizeof(libraw_processed_image_t)); |
293 | | |
294 | | // metadata init |
295 | 0 | ret->type = LIBRAW_IMAGE_BITMAP; |
296 | 0 | ret->height = height; |
297 | 0 | ret->width = width; |
298 | 0 | ret->colors = colors; |
299 | 0 | ret->bits = bps; |
300 | 0 | ret->data_size = ds; |
301 | 0 | copy_mem_image(ret->data, stride, 0); |
302 | |
|
303 | 0 | return ret; |
304 | 0 | } |
305 | | |
306 | | void LibRaw::dcraw_clear_mem(libraw_processed_image_t *p) |
307 | 0 | { |
308 | 0 | if (p) |
309 | 0 | ::free(p); |
310 | 0 | } |