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