Home | History | Annotate | Download | only in source
      1 /*****************************************************************************/
      2 // Copyright 2011 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 /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_jpeg_image.cpp#1 $ */
     10 /* $DateTime: 2012/05/30 13:28:51 $ */
     11 /* $Change: 832332 $ */
     12 /* $Author: tknoll $ */
     13 
     14 /*****************************************************************************/
     15 
     16 #include "dng_jpeg_image.h"
     17 
     18 #include "dng_abort_sniffer.h"
     19 #include "dng_area_task.h"
     20 #include "dng_assertions.h"
     21 #include "dng_host.h"
     22 #include "dng_ifd.h"
     23 #include "dng_image.h"
     24 #include "dng_image_writer.h"
     25 #include "dng_memory_stream.h"
     26 #include "dng_mutex.h"
     27 #include "dng_safe_arithmetic.h"
     28 
     29 /*****************************************************************************/
     30 
     31 dng_jpeg_image::dng_jpeg_image ()
     32 
     33 	:	fImageSize  ()
     34 	,	fTileSize   ()
     35 	,	fUsesStrips (false)
     36 	,	fJPEGTables ()
     37 	,	fJPEGData   ()
     38 
     39 	{
     40 
     41 	}
     42 
     43 /*****************************************************************************/
     44 
     45 class dng_jpeg_image_encode_task : public dng_area_task
     46 	{
     47 
     48 	private:
     49 
     50 		dng_host &fHost;
     51 
     52 		dng_image_writer &fWriter;
     53 
     54 		const dng_image &fImage;
     55 
     56 		dng_jpeg_image &fJPEGImage;
     57 
     58 		uint32 fTileCount;
     59 
     60 		const dng_ifd &fIFD;
     61 
     62 		dng_mutex fMutex;
     63 
     64 		uint32 fNextTileIndex;
     65 
     66 	public:
     67 
     68 		dng_jpeg_image_encode_task (dng_host &host,
     69 									dng_image_writer &writer,
     70 									const dng_image &image,
     71 									dng_jpeg_image &jpegImage,
     72 									uint32 tileCount,
     73 									const dng_ifd &ifd)
     74 
     75 			:	fHost			  (host)
     76 			,	fWriter			  (writer)
     77 			,	fImage			  (image)
     78 			,	fJPEGImage        (jpegImage)
     79 			,	fTileCount		  (tileCount)
     80 			,	fIFD		      (ifd)
     81 			,	fMutex			  ("dng_jpeg_image_encode_task")
     82 			,	fNextTileIndex	  (0)
     83 
     84 			{
     85 
     86 			fMinTaskArea = 16 * 16;
     87 			fUnitCell    = dng_point (16, 16);
     88 			fMaxTileSize = dng_point (16, 16);
     89 
     90 			}
     91 
     92 		void Process (uint32 /* threadIndex */,
     93 					  const dng_rect & /* tile */,
     94 					  dng_abort_sniffer *sniffer)
     95 			{
     96 
     97 			AutoPtr<dng_memory_block> compressedBuffer;
     98 			AutoPtr<dng_memory_block> uncompressedBuffer;
     99 			AutoPtr<dng_memory_block> subTileBlockBuffer;
    100 			AutoPtr<dng_memory_block> tempBuffer;
    101 
    102 			uint32 uncompressedSize = SafeUint32Mult (
    103 				fIFD.fTileLength, fIFD.fTileWidth, fIFD.fSamplesPerPixel);
    104 
    105 			uncompressedBuffer.Reset (fHost.Allocate (uncompressedSize));
    106 
    107 			uint32 tilesAcross = fIFD.TilesAcross ();
    108 
    109 			while (true)
    110 				{
    111 
    112 				uint32 tileIndex;
    113 
    114 					{
    115 
    116 					dng_lock_mutex lock (&fMutex);
    117 
    118 					if (fNextTileIndex == fTileCount)
    119 						{
    120 						return;
    121 						}
    122 
    123 					tileIndex = fNextTileIndex++;
    124 
    125 					}
    126 
    127 				dng_abort_sniffer::SniffForAbort (sniffer);
    128 
    129 				uint32 rowIndex = tileIndex / tilesAcross;
    130 				uint32 colIndex = tileIndex % tilesAcross;
    131 
    132 				dng_rect tileArea = fIFD.TileArea (rowIndex, colIndex);
    133 
    134 				dng_memory_stream stream (fHost.Allocator ());
    135 
    136 				fWriter.WriteTile (fHost,
    137 								   fIFD,
    138 								   stream,
    139 								   fImage,
    140 								   tileArea,
    141 								   1,
    142 								   compressedBuffer,
    143 								   uncompressedBuffer,
    144 								   subTileBlockBuffer,
    145 								   tempBuffer);
    146 
    147 				fJPEGImage.fJPEGData [tileIndex].Reset (stream.AsMemoryBlock (fHost.Allocator ()));
    148 
    149 				}
    150 
    151 			}
    152 
    153 	private:
    154 
    155 		// Hidden copy constructor and assignment operator.
    156 
    157 		dng_jpeg_image_encode_task (const dng_jpeg_image_encode_task &);
    158 
    159 		dng_jpeg_image_encode_task & operator= (const dng_jpeg_image_encode_task &);
    160 
    161 	};
    162 
    163 /*****************************************************************************/
    164 
    165 void dng_jpeg_image::Encode (dng_host &host,
    166 							 const dng_negative &negative,
    167 							 dng_image_writer &writer,
    168 							 const dng_image &image)
    169 	{
    170 
    171 	#if qDNGValidate
    172 	dng_timer timer ("Encode JPEG Proxy time");
    173 	#endif
    174 
    175 	DNG_ASSERT (image.PixelType () == ttByte, "Cannot JPEG encode non-byte image");
    176 
    177 	fImageSize = image.Bounds ().Size ();
    178 
    179 	dng_ifd ifd;
    180 
    181 	ifd.fImageWidth  = fImageSize.h;
    182 	ifd.fImageLength = fImageSize.v;
    183 
    184 	ifd.fSamplesPerPixel = image.Planes ();
    185 
    186 	ifd.fBitsPerSample [0] = 8;
    187 	ifd.fBitsPerSample [1] = 8;
    188 	ifd.fBitsPerSample [2] = 8;
    189 	ifd.fBitsPerSample [3] = 8;
    190 
    191 	ifd.fPhotometricInterpretation = piLinearRaw;
    192 
    193 	ifd.fCompression = ccLossyJPEG;
    194 
    195 	ifd.FindTileSize (512 * 512 * ifd.fSamplesPerPixel);
    196 
    197 	fTileSize.h = ifd.fTileWidth;
    198 	fTileSize.v = ifd.fTileLength;
    199 
    200 	// Need a higher quality for raw proxies than non-raw proxies,
    201 	// since users often perform much greater color changes.  Also, use
    202 	// we are targeting a "large" size proxy (larger than 5MP pixels), or this
    203 	// is a full size proxy, then use a higher quality.
    204 
    205 	bool useHigherQuality = (uint64) ifd.fImageWidth *
    206 							(uint64) ifd.fImageLength > 5000000 ||
    207 							image.Bounds ().Size () == negative.OriginalDefaultFinalSize ();
    208 
    209 	if (negative.ColorimetricReference () == crSceneReferred)
    210 		{
    211 		ifd.fCompressionQuality = useHigherQuality ? 11 : 10;
    212 		}
    213 	else
    214 		{
    215 		ifd.fCompressionQuality = useHigherQuality ? 10 : 8;
    216 		}
    217 
    218 	uint32 tilesAcross = ifd.TilesAcross ();
    219 	uint32 tilesDown   = ifd.TilesDown   ();
    220 
    221 	uint32 tileCount = tilesAcross * tilesDown;
    222 
    223 	fJPEGData.Reset (tileCount);
    224 
    225 	uint32 threadCount = Min_uint32 (tileCount,
    226 									 host.PerformAreaTaskThreads ());
    227 
    228 	dng_jpeg_image_encode_task task (host,
    229 									 writer,
    230 									 image,
    231 									 *this,
    232 									 tileCount,
    233 									 ifd);
    234 
    235 	host.PerformAreaTask (task,
    236 						  dng_rect (0, 0, 16, 16 * threadCount));
    237 
    238 	}
    239 
    240 /*****************************************************************************/
    241 
    242 class dng_jpeg_image_find_digest_task : public dng_area_task
    243 	{
    244 
    245 	private:
    246 
    247 		const dng_jpeg_image &fJPEGImage;
    248 
    249 		uint32 fTileCount;
    250 
    251 		dng_fingerprint *fDigests;
    252 
    253 		dng_mutex fMutex;
    254 
    255 		uint32 fNextTileIndex;
    256 
    257 	public:
    258 
    259 		dng_jpeg_image_find_digest_task (const dng_jpeg_image &jpegImage,
    260 										 uint32 tileCount,
    261 										 dng_fingerprint *digests)
    262 
    263 			:	fJPEGImage        (jpegImage)
    264 			,	fTileCount		  (tileCount)
    265 			,	fDigests		  (digests)
    266 			,	fMutex			  ("dng_jpeg_image_find_digest_task")
    267 			,	fNextTileIndex	  (0)
    268 
    269 			{
    270 
    271 			fMinTaskArea = 16 * 16;
    272 			fUnitCell    = dng_point (16, 16);
    273 			fMaxTileSize = dng_point (16, 16);
    274 
    275 			}
    276 
    277 		void Process (uint32 /* threadIndex */,
    278 					  const dng_rect & /* tile */,
    279 					  dng_abort_sniffer *sniffer)
    280 			{
    281 
    282 			while (true)
    283 				{
    284 
    285 				uint32 tileIndex;
    286 
    287 					{
    288 
    289 					dng_lock_mutex lock (&fMutex);
    290 
    291 					if (fNextTileIndex == fTileCount)
    292 						{
    293 						return;
    294 						}
    295 
    296 					tileIndex = fNextTileIndex++;
    297 
    298 					}
    299 
    300 				dng_abort_sniffer::SniffForAbort (sniffer);
    301 
    302 				dng_md5_printer printer;
    303 
    304 				printer.Process (fJPEGImage.fJPEGData [tileIndex]->Buffer      (),
    305 								 fJPEGImage.fJPEGData [tileIndex]->LogicalSize ());
    306 
    307 				fDigests [tileIndex] = printer.Result ();
    308 
    309 				}
    310 
    311 			}
    312 
    313 	private:
    314 
    315 		// Hidden copy constructor and assignment operator.
    316 
    317 		dng_jpeg_image_find_digest_task (const dng_jpeg_image_find_digest_task &);
    318 
    319 		dng_jpeg_image_find_digest_task & operator= (const dng_jpeg_image_find_digest_task &);
    320 
    321 	};
    322 
    323 /*****************************************************************************/
    324 
    325 dng_fingerprint dng_jpeg_image::FindDigest (dng_host &host) const
    326 	{
    327 
    328 	uint32 tileCount = TileCount ();
    329 
    330 	uint32 arrayCount = tileCount + (fJPEGTables.Get () ? 1 : 0);
    331 
    332 	AutoArray<dng_fingerprint> digests (arrayCount);
    333 
    334 	// Compute digest of each compressed tile.
    335 
    336 		{
    337 
    338 		uint32 threadCount = Min_uint32 (tileCount,
    339 										 host.PerformAreaTaskThreads ());
    340 
    341 		dng_jpeg_image_find_digest_task task (*this,
    342 											  tileCount,
    343 											  digests.Get ());
    344 
    345 		host.PerformAreaTask (task,
    346 							  dng_rect (0, 0, 16, 16 * threadCount));
    347 
    348 		}
    349 
    350 	// Compute digest of JPEG tables, if any.
    351 
    352 	if (fJPEGTables.Get ())
    353 		{
    354 
    355 		dng_md5_printer printer;
    356 
    357 		printer.Process (fJPEGTables->Buffer      (),
    358 						 fJPEGTables->LogicalSize ());
    359 
    360 		digests [tileCount] = printer.Result ();
    361 
    362 		}
    363 
    364 	// Combine digests into a single digest.
    365 
    366 		{
    367 
    368 		dng_md5_printer printer;
    369 
    370 		for (uint32 k = 0; k < arrayCount; k++)
    371 			{
    372 
    373 			printer.Process (digests [k].data,
    374 							 dng_fingerprint::kDNGFingerprintSize);
    375 
    376 			}
    377 
    378 		return printer.Result ();
    379 
    380 		}
    381 
    382 	}
    383 
    384 /*****************************************************************************/
    385 
    386