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