1 /*****************************************************************************/
2 // Copyright 2008-2019 Adobe Systems Incorporated
3 // All Rights Reserved.
4 //
5 // NOTICE: Adobe permits you to use, modify, and distribute this file in
6 // accordance with the terms of the Adobe license agreement accompanying it.
7 /*****************************************************************************/
8
9 #include "dng_opcodes.h"
10
11 #include "dng_bottlenecks.h"
12 #include "dng_exceptions.h"
13 #include "dng_filter_task.h"
14 #include "dng_globals.h"
15 #include "dng_host.h"
16 #include "dng_image.h"
17 #include "dng_negative.h"
18 #include "dng_parse_utils.h"
19 #include "dng_stream.h"
20 #include "dng_tag_values.h"
21
22 /*****************************************************************************/
23
dng_opcode(uint32 opcodeID,uint32 minVersion,uint32 flags)24 dng_opcode::dng_opcode (uint32 opcodeID,
25 uint32 minVersion,
26 uint32 flags)
27
28 : fOpcodeID (opcodeID)
29 , fMinVersion (minVersion)
30 , fFlags (flags)
31 , fWasReadFromStream (false)
32 , fStage (0)
33
34 {
35
36 }
37
38 /*****************************************************************************/
39
dng_opcode(uint32 opcodeID,dng_stream & stream,const char * name)40 dng_opcode::dng_opcode (uint32 opcodeID,
41 dng_stream &stream,
42 const char *name)
43
44 : fOpcodeID (opcodeID)
45 , fMinVersion (0)
46 , fFlags (0)
47 , fWasReadFromStream (true)
48 , fStage (0)
49
50 {
51
52 fMinVersion = stream.Get_uint32 ();
53 fFlags = stream.Get_uint32 ();
54
55 #if qDNGValidate
56
57 if (gVerbose)
58 {
59
60 printf ("\nOpcode: ");
61
62 if (name)
63 {
64 printf ("%s", name);
65 }
66 else
67 {
68 printf ("Unknown (%u)", (unsigned) opcodeID);
69 }
70
71 printf (", minVersion = %u.%u.%u.%u",
72 (unsigned) ((fMinVersion >> 24) & 0x0FF),
73 (unsigned) ((fMinVersion >> 16) & 0x0FF),
74 (unsigned) ((fMinVersion >> 8) & 0x0FF),
75 (unsigned) ((fMinVersion ) & 0x0FF));
76
77 printf (", flags = %u\n", (unsigned) fFlags);
78
79 }
80
81 #else
82
83 (void) name;
84
85 #endif
86
87 }
88
89 /*****************************************************************************/
90
~dng_opcode()91 dng_opcode::~dng_opcode ()
92 {
93
94 }
95
96 /*****************************************************************************/
97
PutData(dng_stream & stream) const98 void dng_opcode::PutData (dng_stream &stream) const
99 {
100
101 // No data by default
102
103 stream.Put_uint32 (0);
104
105 }
106
107 /*****************************************************************************/
108
AboutToApply(dng_host & host,dng_negative & negative,const dng_rect & imageBounds,uint32 imagePlanes)109 bool dng_opcode::AboutToApply (dng_host &host,
110 dng_negative &negative,
111 const dng_rect &imageBounds,
112 uint32 imagePlanes)
113 {
114
115 if (SkipIfPreview () && host.ForPreview ())
116 {
117
118 negative.SetIsPreview (true);
119
120 }
121
122 else if (MinVersion () > dngVersion_Current &&
123 WasReadFromStream ())
124 {
125
126 if (!Optional ())
127 {
128
129 // Somebody screwed up computing the DNGBackwardVersion...
130
131 ThrowBadFormat ();
132
133 }
134
135 }
136
137 else if (!IsValidForNegative (negative))
138 {
139
140 ThrowBadFormat ();
141
142 }
143
144 else if (!IsNOP ())
145 {
146
147 DoAboutToApply (host,
148 negative,
149 imageBounds,
150 imagePlanes);
151
152 return true;
153
154 }
155
156 return false;
157
158 }
159
160 /*****************************************************************************/
161
dng_opcode_Unknown(dng_host & host,uint32 opcodeID,dng_stream & stream)162 dng_opcode_Unknown::dng_opcode_Unknown (dng_host &host,
163 uint32 opcodeID,
164 dng_stream &stream)
165
166 : dng_opcode (opcodeID,
167 stream,
168 NULL)
169
170 , fData ()
171
172 {
173
174 uint32 size = stream.Get_uint32 ();
175
176 if (size)
177 {
178
179 fData.Reset (host.Allocate (size));
180
181 stream.Get (fData->Buffer (),
182 fData->LogicalSize ());
183
184 #if qDNGValidate
185
186 if (gVerbose)
187 {
188
189 DumpHexAscii (fData->Buffer_uint8 (),
190 fData->LogicalSize ());
191
192 }
193
194 #endif
195
196 }
197
198 }
199
200 /*****************************************************************************/
201
PutData(dng_stream & stream) const202 void dng_opcode_Unknown::PutData (dng_stream &stream) const
203 {
204
205 if (fData.Get ())
206 {
207
208 stream.Put_uint32 (fData->LogicalSize ());
209
210 stream.Put (fData->Buffer (),
211 fData->LogicalSize ());
212
213 }
214
215 else
216 {
217
218 stream.Put_uint32 (0);
219
220 }
221
222 }
223
224 /*****************************************************************************/
225
Apply(dng_host &,dng_negative &,AutoPtr<dng_image> &)226 void dng_opcode_Unknown::Apply (dng_host & /* host */,
227 dng_negative & /* negative */,
228 AutoPtr<dng_image> & /* image */)
229 {
230
231 // We should never need to apply an unknown opcode.
232
233 if (!Optional ())
234 {
235
236 ThrowBadFormat ();
237
238 }
239
240 }
241
242 /*****************************************************************************/
243
244 class dng_filter_opcode_task: public dng_filter_task
245 {
246
247 private:
248
249 dng_filter_opcode &fOpcode;
250
251 dng_negative &fNegative;
252
253 public:
254
dng_filter_opcode_task(dng_filter_opcode & opcode,dng_negative & negative,const dng_image & srcImage,dng_image & dstImage)255 dng_filter_opcode_task (dng_filter_opcode &opcode,
256 dng_negative &negative,
257 const dng_image &srcImage,
258 dng_image &dstImage)
259
260 : dng_filter_task ("dng_filter_opcode_task",
261 srcImage,
262 dstImage)
263
264 , fOpcode (opcode)
265 , fNegative (negative)
266
267 {
268
269 fSrcPixelType = fOpcode.BufferPixelType (srcImage.PixelType ());
270
271 fDstPixelType = fSrcPixelType;
272
273 fSrcRepeat = opcode.SrcRepeat ();
274
275 }
276
SrcArea(const dng_rect & dstArea)277 virtual dng_rect SrcArea (const dng_rect &dstArea)
278 {
279
280 return fOpcode.SrcArea (dstArea,
281 fDstImage.Bounds ());
282
283 }
284
SrcTileSize(const dng_point & dstTileSize)285 virtual dng_point SrcTileSize (const dng_point &dstTileSize)
286 {
287
288 return fOpcode.SrcTileSize (dstTileSize,
289 fDstImage.Bounds ());
290
291 }
292
ProcessArea(uint32 threadIndex,dng_pixel_buffer & srcBuffer,dng_pixel_buffer & dstBuffer)293 virtual void ProcessArea (uint32 threadIndex,
294 dng_pixel_buffer &srcBuffer,
295 dng_pixel_buffer &dstBuffer)
296 {
297
298 fOpcode.ProcessArea (fNegative,
299 threadIndex,
300 srcBuffer,
301 dstBuffer,
302 dstBuffer.Area (),
303 fDstImage.Bounds ());
304
305 }
306
Start(uint32 threadCount,const dng_rect & dstArea,const dng_point & tileSize,dng_memory_allocator * allocator,dng_abort_sniffer * sniffer)307 virtual void Start (uint32 threadCount,
308 const dng_rect &dstArea,
309 const dng_point &tileSize,
310 dng_memory_allocator *allocator,
311 dng_abort_sniffer *sniffer)
312 {
313
314 dng_filter_task::Start (threadCount,
315 dstArea,
316 tileSize,
317 allocator,
318 sniffer);
319
320 fOpcode.Prepare (fNegative,
321 threadCount,
322 tileSize,
323 fDstImage.Bounds (),
324 fDstImage.Planes (),
325 fDstPixelType,
326 *allocator);
327
328 }
329
330 };
331
332 /*****************************************************************************/
333
dng_filter_opcode(uint32 opcodeID,uint32 minVersion,uint32 flags)334 dng_filter_opcode::dng_filter_opcode (uint32 opcodeID,
335 uint32 minVersion,
336 uint32 flags)
337
338 : dng_opcode (opcodeID,
339 minVersion,
340 flags)
341
342 {
343
344 }
345
346 /*****************************************************************************/
347
dng_filter_opcode(uint32 opcodeID,dng_stream & stream,const char * name)348 dng_filter_opcode::dng_filter_opcode (uint32 opcodeID,
349 dng_stream &stream,
350 const char *name)
351
352 : dng_opcode (opcodeID,
353 stream,
354 name)
355
356 {
357
358 }
359
360 /*****************************************************************************/
361
Apply(dng_host & host,dng_negative & negative,AutoPtr<dng_image> & image)362 void dng_filter_opcode::Apply (dng_host &host,
363 dng_negative &negative,
364 AutoPtr<dng_image> &image)
365 {
366
367 dng_rect modifiedBounds = ModifiedBounds (image->Bounds ());
368
369 if (modifiedBounds.NotEmpty ())
370 {
371
372 // Allocate destination image.
373
374 AutoPtr<dng_image> dstImage;
375
376 // If we are processing the entire image, allocate an
377 // undefined image.
378
379 if (modifiedBounds == image->Bounds ())
380 {
381
382 dstImage.Reset (host.Make_dng_image (image->Bounds (),
383 image->Planes (),
384 image->PixelType ()));
385
386 }
387
388 // Else start with a clone of the existing image.
389
390 else
391 {
392
393 dstImage.Reset (image->Clone ());
394
395 }
396
397 // Filter the image.
398
399 dng_filter_opcode_task task (*this,
400 negative,
401 *image,
402 *dstImage);
403
404 host.PerformAreaTask (task,
405 modifiedBounds);
406
407 // Return the new image.
408
409 image.Reset (dstImage.Release ());
410
411 }
412
413 }
414
415 /*****************************************************************************/
416
417 class dng_inplace_opcode_task: public dng_area_task
418 {
419
420 private:
421
422 dng_inplace_opcode &fOpcode;
423
424 dng_negative &fNegative;
425
426 dng_image &fImage;
427
428 uint32 fPixelType;
429
430 AutoPtr<dng_memory_block> fBuffer [kMaxMPThreads];
431
432 public:
433
dng_inplace_opcode_task(dng_inplace_opcode & opcode,dng_negative & negative,dng_image & image)434 dng_inplace_opcode_task (dng_inplace_opcode &opcode,
435 dng_negative &negative,
436 dng_image &image)
437
438 : dng_area_task ("dng_inplace_opcode_task")
439
440 , fOpcode (opcode)
441 , fNegative (negative)
442 , fImage (image)
443 , fPixelType (opcode.BufferPixelType (image.PixelType ()))
444
445 {
446
447 }
448
Start(uint32 threadCount,const dng_rect &,const dng_point & tileSize,dng_memory_allocator * allocator,dng_abort_sniffer *)449 virtual void Start (uint32 threadCount,
450 const dng_rect & /* dstArea */,
451 const dng_point &tileSize,
452 dng_memory_allocator *allocator,
453 dng_abort_sniffer * /* sniffer */)
454 {
455
456 uint32 bufferSize = ComputeBufferSize (fPixelType,
457 tileSize,
458 fImage.Planes (),
459 padSIMDBytes);
460
461 for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++)
462 {
463
464 fBuffer [threadIndex] . Reset (allocator->Allocate (bufferSize));
465
466 }
467
468 fOpcode.Prepare (fNegative,
469 threadCount,
470 tileSize,
471 fImage.Bounds (),
472 fImage.Planes (),
473 fPixelType,
474 *allocator);
475
476 }
477
Process(uint32 threadIndex,const dng_rect & tile,dng_abort_sniffer *)478 virtual void Process (uint32 threadIndex,
479 const dng_rect &tile,
480 dng_abort_sniffer * /* sniffer */)
481 {
482
483 // Setup buffer.
484
485 dng_pixel_buffer buffer (tile,
486 0,
487 fImage.Planes (),
488 fPixelType,
489 pcRowInterleavedAlignSIMD,
490 fBuffer [threadIndex]->Buffer ());
491
492 // Get source pixels.
493
494 fImage.Get (buffer);
495
496 // Process area.
497
498 fOpcode.ProcessArea (fNegative,
499 threadIndex,
500 buffer,
501 tile,
502 fImage.Bounds ());
503
504 // Save result pixels.
505
506 fImage.Put (buffer);
507
508 }
509
510 };
511
512 /*****************************************************************************/
513
dng_inplace_opcode(uint32 opcodeID,uint32 minVersion,uint32 flags)514 dng_inplace_opcode::dng_inplace_opcode (uint32 opcodeID,
515 uint32 minVersion,
516 uint32 flags)
517
518 : dng_opcode (opcodeID,
519 minVersion,
520 flags)
521
522 {
523
524 }
525
526 /*****************************************************************************/
527
dng_inplace_opcode(uint32 opcodeID,dng_stream & stream,const char * name)528 dng_inplace_opcode::dng_inplace_opcode (uint32 opcodeID,
529 dng_stream &stream,
530 const char *name)
531
532 : dng_opcode (opcodeID,
533 stream,
534 name)
535
536 {
537
538 }
539
540 /*****************************************************************************/
541
Apply(dng_host & host,dng_negative & negative,AutoPtr<dng_image> & image)542 void dng_inplace_opcode::Apply (dng_host &host,
543 dng_negative &negative,
544 AutoPtr<dng_image> &image)
545 {
546
547 dng_rect modifiedBounds = ModifiedBounds (image->Bounds ());
548
549 if (modifiedBounds.NotEmpty ())
550 {
551
552 dng_inplace_opcode_task task (*this,
553 negative,
554 *image);
555
556 host.PerformAreaTask (task,
557 modifiedBounds);
558
559 }
560
561 }
562
563 /*****************************************************************************/
564