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
17 #if defined (USE_GPRSDK) && !defined(USE_DNGSDK)
18 #error GPR (GoPro) SDK should be used with Adobe DNG SDK
19 #endif
20 #ifdef USE_DNGSDK
21 #include "dng_read_image.h"
22 #endif
23 #ifdef USE_GPRSDK
24 #include "gpr_read_image.h"
25 #endif
26
27 #ifdef USE_DNGSDK
search_single_ifd(const std::vector<dng_ifd * > & v,uint64 offset,int & idx,dng_stream & stream)28 static dng_ifd* search_single_ifd(const std::vector <dng_ifd *>& v, uint64 offset, int& idx, dng_stream& stream)
29 {
30 idx = -1;
31 for (int i = 0; i < v.size(); i++)
32 {
33 if (!v[i]) continue;
34 if (v[i]->fTileOffsetsOffset == offset)
35 {
36 idx = i;
37 return v[i];
38 }
39 else if (v[i]->fTileOffsetsCount == 1 && v[i]->fTileOffset[0] == offset)
40 {
41 idx = i;
42 return v[i];
43 }
44 else if (v[i]->fTileOffsetsCount > dng_ifd::kMaxTileInfo)
45 {
46 uint64 p = stream.Position();
47 stream.SetReadPosition(v[i]->fTileOffsetsOffset);
48 int32 oo = stream.TagValue_uint32(v[i]->fTileOffsetsType);
49 stream.SetReadPosition(p);
50 if (oo == offset)
51 {
52 idx = i;
53 return v[i];
54 }
55 }
56 }
57 return NULL;
58 }
59
search_for_ifd(const dng_info & info,uint64 offset,ushort w,ushort h,int & ifdIndex,dng_stream & stream)60 static dng_ifd* search_for_ifd(const dng_info& info, uint64 offset, ushort w, ushort h, int& ifdIndex, dng_stream& stream)
61 {
62 dng_ifd *ret = 0;
63 ret = search_single_ifd(info.fIFD, offset, ifdIndex, stream);
64 int dummy;
65 if (!ret) ret = search_single_ifd(info.fChainedIFD, offset, dummy, stream);
66 if (!ret)
67 {
68 for (int c = 0; !ret && c < info.fChainedSubIFD.size(); c++)
69 ret = search_single_ifd(info.fChainedSubIFD[c], offset, dummy, stream);
70 }
71 if (ret && (ret->fImageLength == h) && ret->fImageWidth == w)
72 return ret;
73 ifdIndex = -1;
74 return 0;
75 }
76 #endif
77
valid_for_dngsdk()78 int LibRaw::valid_for_dngsdk()
79 {
80 #ifndef USE_DNGSDK
81 return 0;
82 #else
83 if (!imgdata.idata.dng_version)
84 return 0;
85 if (libraw_internal_data.unpacker_data.tiff_compress == 34892
86 && libraw_internal_data.unpacker_data.tiff_bps == 8
87 && libraw_internal_data.unpacker_data.tiff_samples == 3
88 && load_raw == &LibRaw::lossy_dng_load_raw
89 )
90 {
91 if (!dnghost)
92 return 0;
93 dng_host *host = static_cast<dng_host *>(dnghost);
94 libraw_dng_stream stream(libraw_internal_data.internal_data.input);
95 AutoPtr<dng_negative> negative;
96 negative.Reset(host->Make_dng_negative());
97 dng_info info;
98 info.Parse(*host, stream);
99 info.PostParse(*host);
100 if (!info.IsValidDNG())
101 return 0;
102 negative->Parse(*host, stream, info);
103 negative->PostParse(*host, stream, info);
104 int ifdindex = -1;
105 dng_ifd *rawIFD = search_for_ifd(info, libraw_internal_data.unpacker_data.data_offset, imgdata.sizes.raw_width, imgdata.sizes.raw_height, ifdindex,stream);
106 if (rawIFD && ifdindex >= 0 && ifdindex == info.fMainIndex)
107 return 1;
108 return 0;
109 }
110
111 #ifdef USE_GPRSDK
112 if (load_raw == &LibRaw::vc5_dng_load_raw_placeholder) // regardless of flags or use_dngsdk value!
113 return 1;
114 #endif
115 if (!imgdata.params.use_dngsdk)
116 return 0;
117 if (load_raw == &LibRaw::lossy_dng_load_raw) // WHY??
118 return 0;
119 if (load_raw ==
120 &LibRaw::float_dng_load_raw_placeholder) // regardless of flags!
121 return 1;
122 if (is_floating_point() && (imgdata.params.use_dngsdk & LIBRAW_DNG_FLOAT))
123 return 1;
124 if (!imgdata.idata.filters && (imgdata.params.use_dngsdk & LIBRAW_DNG_LINEAR))
125 return 1;
126 if (libraw_internal_data.unpacker_data.tiff_bps == 8 &&
127 (imgdata.params.use_dngsdk & LIBRAW_DNG_8BIT))
128 return 1;
129 if (libraw_internal_data.unpacker_data.tiff_compress == 8 &&
130 (imgdata.params.use_dngsdk & LIBRAW_DNG_DEFLATE))
131 return 1;
132 if (libraw_internal_data.unpacker_data.tiff_samples == 2)
133 return 0; // Always deny 2-samples (old fuji superccd)
134 if (imgdata.idata.filters == 9 &&
135 (imgdata.params.use_dngsdk & LIBRAW_DNG_XTRANS))
136 return 1;
137 if (is_fuji_rotated())
138 return 0; // refuse
139 if (imgdata.params.use_dngsdk & LIBRAW_DNG_OTHER)
140 return 1;
141 return 0;
142 #endif
143 }
144
145
146
147
try_dngsdk()148 int LibRaw::try_dngsdk()
149 {
150 #ifdef USE_DNGSDK
151 if (!dnghost)
152 return LIBRAW_UNSPECIFIED_ERROR;
153
154 dng_host *host = static_cast<dng_host *>(dnghost);
155
156 try
157 {
158 libraw_dng_stream stream(libraw_internal_data.internal_data.input);
159
160 AutoPtr<dng_negative> negative;
161 negative.Reset(host->Make_dng_negative());
162
163 dng_info info;
164 info.Parse(*host, stream);
165 info.PostParse(*host);
166
167 if (!info.IsValidDNG())
168 {
169 return LIBRAW_DATA_ERROR;
170 }
171 negative->Parse(*host, stream, info);
172 negative->PostParse(*host, stream, info);
173 int ifdindex;
174 dng_ifd *rawIFD = search_for_ifd(info,libraw_internal_data.unpacker_data.data_offset,imgdata.sizes.raw_width,imgdata.sizes.raw_height,ifdindex,stream);
175 if(!rawIFD)
176 return LIBRAW_DATA_ERROR;
177
178 AutoPtr<dng_simple_image> stage2;
179 bool stage23used = false;
180 bool zerocopy = false;
181
182 //(new dng_simple_image(rawIFD->Bounds(), rawIFD->fSamplesPerPixel, rawIFD->PixelType(), host->Allocator()));
183
184 if (((libraw_internal_data.unpacker_data.tiff_compress == 34892
185 && libraw_internal_data.unpacker_data.tiff_bps == 8
186 && libraw_internal_data.unpacker_data.tiff_samples == 3
187 && load_raw == &LibRaw::lossy_dng_load_raw) ||
188 (imgdata.params.raw_processing_options & (LIBRAW_PROCESSING_DNG_STAGE2| LIBRAW_PROCESSING_DNG_STAGE3)))
189 && ifdindex >= 0)
190 {
191 if (info.fMainIndex != ifdindex)
192 info.fMainIndex = ifdindex;
193
194 negative->ReadStage1Image(*host, stream, info);
195 negative->BuildStage2Image(*host);
196 imgdata.process_warnings |= LIBRAW_WARN_DNG_STAGE2_APPLIED;
197 if (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_DNG_STAGE3)
198 {
199 negative->BuildStage3Image(*host);
200 stage2.Reset((dng_simple_image*)negative->Stage3Image());
201 imgdata.process_warnings |= LIBRAW_WARN_DNG_STAGE3_APPLIED;
202 }
203 else
204 stage2.Reset((dng_simple_image*)negative->Stage2Image());
205 stage23used = true;
206 }
207 else
208 {
209 stage2.Reset(new dng_simple_image(rawIFD->Bounds(), rawIFD->fSamplesPerPixel, rawIFD->PixelType(), host->Allocator()));
210 #ifdef USE_GPRSDK
211 if (libraw_internal_data.unpacker_data.tiff_compress == 9)
212 {
213 gpr_allocator allocator;
214 allocator.Alloc = ::malloc;
215 allocator.Free = ::free;
216 gpr_buffer_auto vc5_image_obj(allocator.Alloc, allocator.Free);
217
218 gpr_read_image reader(&vc5_image_obj);
219 reader.Read(*host, *rawIFD, stream, *stage2.Get(), NULL, NULL);
220 }
221 else
222 #endif
223 {
224 dng_read_image reader;
225 reader.Read(*host, *rawIFD, stream, *stage2.Get(), NULL, NULL);
226 }
227 }
228
229 if (stage2->Bounds().W() != S.raw_width ||
230 stage2->Bounds().H() != S.raw_height)
231 {
232 if (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_DNG_ALLOWSIZECHANGE)
233 {
234 S.raw_width = S.width = stage2->Bounds().W();
235 S.left_margin = 0;
236 S.raw_height = S.height = stage2->Bounds().H();
237 S.top_margin = 0;
238 }
239 else
240 {
241 stage2.Release(); // It holds copy to internal dngnegative
242 return LIBRAW_DATA_ERROR;
243 }
244 }
245 if (stage23used)
246 {
247 if (stage2->Planes() > 1)
248 {
249 imgdata.idata.filters = 0;
250 imgdata.idata.colors = stage2->Planes();
251 }
252 // reset BL and whitepoint
253 imgdata.color.black = 0;
254 memset(imgdata.color.cblack, 0, sizeof(imgdata.color.cblack));
255 imgdata.color.maximum = 0xffff;
256 }
257
258 int pplanes = stage2->Planes();
259 int ptype = stage2->PixelType();
260
261 dng_pixel_buffer buffer;
262 stage2->GetPixelBuffer(buffer);
263
264 int pixels = stage2->Bounds().H() * stage2->Bounds().W() * pplanes;
265
266 if (ptype == ttShort && !stage23used && !is_curve_linear())
267 {
268 imgdata.rawdata.raw_alloc = malloc(pixels * TagTypeSize(ptype));
269 ushort *src = (ushort *)buffer.fData;
270 ushort *dst = (ushort *)imgdata.rawdata.raw_alloc;
271 for (int i = 0; i < pixels; i++)
272 dst[i] = imgdata.color.curve[src[i]];
273 S.raw_pitch = S.raw_width * pplanes * TagTypeSize(ptype);
274
275 }
276 else if (ptype == ttByte)
277 {
278 imgdata.rawdata.raw_alloc = malloc(pixels * TagTypeSize(ttShort));
279 unsigned char *src = (unsigned char *)buffer.fData;
280 ushort *dst = (ushort *)imgdata.rawdata.raw_alloc;
281 if (is_curve_linear())
282 {
283 for (int i = 0; i < pixels; i++)
284 dst[i] = src[i];
285 }
286 else
287 {
288 for (int i = 0; i < pixels; i++)
289 dst[i] = imgdata.color.curve[src[i]];
290 }
291 S.raw_pitch = S.raw_width * pplanes * TagTypeSize(ttShort);
292 }
293 else
294 {
295 // Alloc
296 if ((imgdata.params.raw_processing_options & LIBRAW_PROCESSING_DNGSDK_ZEROCOPY) && !stage23used)
297 {
298 zerocopy = true;
299 }
300 else
301 {
302 imgdata.rawdata.raw_alloc = malloc(pixels * TagTypeSize(ptype));
303 memmove(imgdata.rawdata.raw_alloc, buffer.fData,
304 pixels * TagTypeSize(ptype));
305 }
306 S.raw_pitch = S.raw_width * pplanes * TagTypeSize(ptype);
307 }
308
309 if (stage23used)
310 stage2.Release();
311
312 if (zerocopy)
313 {
314 switch (ptype)
315 {
316 case ttFloat:
317 if (pplanes == 1)
318 imgdata.rawdata.float_image = (float *)buffer.fData;
319 else if (pplanes == 3)
320 imgdata.rawdata.float3_image = (float(*)[3])buffer.fData;
321 else if (pplanes == 4)
322 imgdata.rawdata.float4_image = (float(*)[4])buffer.fData;
323 break;
324
325 case ttShort:
326 if (pplanes == 1)
327 imgdata.rawdata.raw_image = (ushort *)buffer.fData;
328 else if (pplanes == 3)
329 imgdata.rawdata.color3_image = (ushort(*)[3])buffer.fData;
330 else if (pplanes == 4)
331 imgdata.rawdata.color4_image = (ushort(*)[4])buffer.fData;
332 break;
333 default:
334 /* do nothing */
335 break;
336 }
337 }
338 else
339 {
340 switch (ptype)
341 {
342 case ttFloat:
343 if (pplanes == 1)
344 imgdata.rawdata.float_image = (float *)imgdata.rawdata.raw_alloc;
345 else if (pplanes == 3)
346 imgdata.rawdata.float3_image = (float(*)[3])imgdata.rawdata.raw_alloc;
347 else if (pplanes == 4)
348 imgdata.rawdata.float4_image = (float(*)[4])imgdata.rawdata.raw_alloc;
349 break;
350
351 case ttByte:
352 case ttShort:
353 if (pplanes == 1)
354 imgdata.rawdata.raw_image = (ushort *)imgdata.rawdata.raw_alloc;
355 else if (pplanes == 3)
356 imgdata.rawdata.color3_image =
357 (ushort(*)[3])imgdata.rawdata.raw_alloc;
358 else if (pplanes == 4)
359 imgdata.rawdata.color4_image =
360 (ushort(*)[4])imgdata.rawdata.raw_alloc;
361 break;
362 default:
363 /* do nothing */
364 break;
365 }
366 }
367 if (zerocopy)
368 {
369 dng_negative *stolen = negative.Release();
370 dngnegative = stolen;
371 dng_simple_image *simage = stage2.Release();
372 dngimage = simage;
373 }
374 }
375 catch (...)
376 {
377 return LIBRAW_UNSPECIFIED_ERROR;
378 }
379 return imgdata.rawdata.raw_alloc ? LIBRAW_SUCCESS : LIBRAW_UNSPECIFIED_ERROR;
380 #else
381 return LIBRAW_UNSPECIFIED_ERROR;
382 #endif
383 }
set_dng_host(void * p)384 void LibRaw::set_dng_host(void *p)
385 {
386 #ifdef USE_DNGSDK
387 dnghost = p;
388 #endif
389 }
390