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