16e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim/*****************************************************************************/
26e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// Copyright 2011 Adobe Systems Incorporated
36e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// All Rights Reserved.
46e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim//
56e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// NOTICE:  Adobe permits you to use, modify, and distribute this file in
66e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// accordance with the terms of the Adobe license agreement accompanying it.
76e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim/*****************************************************************************/
86e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
96e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_jpeg_image.cpp#1 $ */
106e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim/* $DateTime: 2012/05/30 13:28:51 $ */
116e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim/* $Change: 832332 $ */
126e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim/* $Author: tknoll $ */
136e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
146e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim/*****************************************************************************/
156e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
166e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include "dng_jpeg_image.h"
176e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
186e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include "dng_abort_sniffer.h"
196e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include "dng_area_task.h"
206e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include "dng_assertions.h"
216e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include "dng_host.h"
226e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include "dng_ifd.h"
236e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include "dng_image.h"
246e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include "dng_image_writer.h"
256e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include "dng_memory_stream.h"
266e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include "dng_mutex.h"
276e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include "dng_safe_arithmetic.h"
286e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
296e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim/*****************************************************************************/
306e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
316e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimdng_jpeg_image::dng_jpeg_image ()
326e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
336e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	:	fImageSize  ()
346e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	,	fTileSize   ()
356e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	,	fUsesStrips (false)
366e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	,	fJPEGTables ()
376e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	,	fJPEGData   ()
386e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
396e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	{
406e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
416e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	}
426e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
436e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim/*****************************************************************************/
446e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
456e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimclass dng_jpeg_image_encode_task : public dng_area_task
466e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	{
476e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
486e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	private:
496e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
506e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		dng_host &fHost;
516e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
526e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		dng_image_writer &fWriter;
536e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
546e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		const dng_image &fImage;
556e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
566e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		dng_jpeg_image &fJPEGImage;
576e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
586e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		uint32 fTileCount;
596e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
606e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		const dng_ifd &fIFD;
616e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
626e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		dng_mutex fMutex;
636e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
646e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		uint32 fNextTileIndex;
656e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
666e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	public:
676e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
686e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		dng_jpeg_image_encode_task (dng_host &host,
696e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim									dng_image_writer &writer,
706e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim									const dng_image &image,
716e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim									dng_jpeg_image &jpegImage,
726e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim									uint32 tileCount,
736e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim									const dng_ifd &ifd)
746e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
756e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			:	fHost			  (host)
766e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			,	fWriter			  (writer)
776e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			,	fImage			  (image)
786e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			,	fJPEGImage        (jpegImage)
796e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			,	fTileCount		  (tileCount)
806e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			,	fIFD		      (ifd)
816e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			,	fMutex			  ("dng_jpeg_image_encode_task")
826e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			,	fNextTileIndex	  (0)
836e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
846e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			{
856e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
866e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			fMinTaskArea = 16 * 16;
876e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			fUnitCell    = dng_point (16, 16);
886e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			fMaxTileSize = dng_point (16, 16);
896e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
906e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			}
916e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
926e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		void Process (uint32 /* threadIndex */,
936e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim					  const dng_rect & /* tile */,
946e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim					  dng_abort_sniffer *sniffer)
956e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			{
966e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
976e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			AutoPtr<dng_memory_block> compressedBuffer;
986e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			AutoPtr<dng_memory_block> uncompressedBuffer;
996e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			AutoPtr<dng_memory_block> subTileBlockBuffer;
1006e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			AutoPtr<dng_memory_block> tempBuffer;
1016e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1026e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			uint32 uncompressedSize = SafeUint32Mult (
1036e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				fIFD.fTileLength, fIFD.fTileWidth, fIFD.fSamplesPerPixel);
1046e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1056e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			uncompressedBuffer.Reset (fHost.Allocate (uncompressedSize));
1066e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1076e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			uint32 tilesAcross = fIFD.TilesAcross ();
1086e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1096e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			while (true)
1106e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				{
1116e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1126e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				uint32 tileIndex;
1136e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1146e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim					{
1156e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1166e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim					dng_lock_mutex lock (&fMutex);
1176e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1186e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim					if (fNextTileIndex == fTileCount)
1196e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim						{
1206e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim						return;
1216e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim						}
1226e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1236e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim					tileIndex = fNextTileIndex++;
1246e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1256e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim					}
1266e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1276e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				dng_abort_sniffer::SniffForAbort (sniffer);
1286e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1296e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				uint32 rowIndex = tileIndex / tilesAcross;
1306e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				uint32 colIndex = tileIndex % tilesAcross;
1316e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1326e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				dng_rect tileArea = fIFD.TileArea (rowIndex, colIndex);
1336e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1346e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				dng_memory_stream stream (fHost.Allocator ());
1356e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1366e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				fWriter.WriteTile (fHost,
1376e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim								   fIFD,
1386e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim								   stream,
1396e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim								   fImage,
1406e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim								   tileArea,
1416e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim								   1,
1426e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim								   compressedBuffer,
1436e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim								   uncompressedBuffer,
1446e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim								   subTileBlockBuffer,
1456e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim								   tempBuffer);
1466e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1476e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				fJPEGImage.fJPEGData [tileIndex].Reset (stream.AsMemoryBlock (fHost.Allocator ()));
1486e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1496e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				}
1506e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1516e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			}
1526e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1536e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	private:
1546e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1556e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		// Hidden copy constructor and assignment operator.
1566e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1576e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		dng_jpeg_image_encode_task (const dng_jpeg_image_encode_task &);
1586e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1596e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		dng_jpeg_image_encode_task & operator= (const dng_jpeg_image_encode_task &);
1606e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1616e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	};
1626e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1636e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim/*****************************************************************************/
1646e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1656e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimvoid dng_jpeg_image::Encode (dng_host &host,
1666e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim							 const dng_negative &negative,
1676e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim							 dng_image_writer &writer,
1686e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim							 const dng_image &image)
1696e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	{
1706e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1716e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	#if qDNGValidate
1726e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	dng_timer timer ("Encode JPEG Proxy time");
1736e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	#endif
1746e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1756e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	DNG_ASSERT (image.PixelType () == ttByte, "Cannot JPEG encode non-byte image");
1766e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1776e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	fImageSize = image.Bounds ().Size ();
1786e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1796e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	dng_ifd ifd;
1806e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1816e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	ifd.fImageWidth  = fImageSize.h;
1826e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	ifd.fImageLength = fImageSize.v;
1836e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1846e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	ifd.fSamplesPerPixel = image.Planes ();
1856e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1866e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	ifd.fBitsPerSample [0] = 8;
1876e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	ifd.fBitsPerSample [1] = 8;
1886e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	ifd.fBitsPerSample [2] = 8;
1896e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	ifd.fBitsPerSample [3] = 8;
1906e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1916e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	ifd.fPhotometricInterpretation = piLinearRaw;
1926e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1936e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	ifd.fCompression = ccLossyJPEG;
1946e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1956e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	ifd.FindTileSize (512 * 512 * ifd.fSamplesPerPixel);
1966e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
1976e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	fTileSize.h = ifd.fTileWidth;
1986e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	fTileSize.v = ifd.fTileLength;
1996e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2006e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	// Need a higher quality for raw proxies than non-raw proxies,
2016e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	// since users often perform much greater color changes.  Also, use
2026e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	// we are targeting a "large" size proxy (larger than 5MP pixels), or this
2036e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	// is a full size proxy, then use a higher quality.
2046e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2056e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	bool useHigherQuality = (uint64) ifd.fImageWidth *
2066e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim							(uint64) ifd.fImageLength > 5000000 ||
2076e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim							image.Bounds ().Size () == negative.OriginalDefaultFinalSize ();
2086e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2096e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	if (negative.ColorimetricReference () == crSceneReferred)
2106e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		{
2116e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		ifd.fCompressionQuality = useHigherQuality ? 11 : 10;
2126e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		}
2136e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	else
2146e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		{
2156e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		ifd.fCompressionQuality = useHigherQuality ? 10 : 8;
2166e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		}
2176e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2186e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	uint32 tilesAcross = ifd.TilesAcross ();
2196e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	uint32 tilesDown   = ifd.TilesDown   ();
2206e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2216e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	uint32 tileCount = tilesAcross * tilesDown;
2226e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2236e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	fJPEGData.Reset (tileCount);
2246e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2256e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	uint32 threadCount = Min_uint32 (tileCount,
2266e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim									 host.PerformAreaTaskThreads ());
2276e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2286e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	dng_jpeg_image_encode_task task (host,
2296e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim									 writer,
2306e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim									 image,
2316e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim									 *this,
2326e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim									 tileCount,
2336e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim									 ifd);
2346e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2356e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	host.PerformAreaTask (task,
2366e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim						  dng_rect (0, 0, 16, 16 * threadCount));
2376e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2386e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	}
2396e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2406e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim/*****************************************************************************/
2416e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2426e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimclass dng_jpeg_image_find_digest_task : public dng_area_task
2436e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	{
2446e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2456e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	private:
2466e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2476e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		const dng_jpeg_image &fJPEGImage;
2486e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2496e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		uint32 fTileCount;
2506e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2516e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		dng_fingerprint *fDigests;
2526e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2536e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		dng_mutex fMutex;
2546e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2556e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		uint32 fNextTileIndex;
2566e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2576e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	public:
2586e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2596e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		dng_jpeg_image_find_digest_task (const dng_jpeg_image &jpegImage,
2606e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim										 uint32 tileCount,
2616e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim										 dng_fingerprint *digests)
2626e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2636e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			:	fJPEGImage        (jpegImage)
2646e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			,	fTileCount		  (tileCount)
2656e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			,	fDigests		  (digests)
2666e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			,	fMutex			  ("dng_jpeg_image_find_digest_task")
2676e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			,	fNextTileIndex	  (0)
2686e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2696e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			{
2706e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2716e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			fMinTaskArea = 16 * 16;
2726e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			fUnitCell    = dng_point (16, 16);
2736e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			fMaxTileSize = dng_point (16, 16);
2746e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2756e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			}
2766e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2776e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		void Process (uint32 /* threadIndex */,
2786e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim					  const dng_rect & /* tile */,
2796e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim					  dng_abort_sniffer *sniffer)
2806e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			{
2816e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2826e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			while (true)
2836e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				{
2846e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2856e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				uint32 tileIndex;
2866e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2876e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim					{
2886e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2896e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim					dng_lock_mutex lock (&fMutex);
2906e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2916e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim					if (fNextTileIndex == fTileCount)
2926e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim						{
2936e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim						return;
2946e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim						}
2956e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2966e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim					tileIndex = fNextTileIndex++;
2976e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
2986e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim					}
2996e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3006e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				dng_abort_sniffer::SniffForAbort (sniffer);
3016e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3026e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				dng_md5_printer printer;
3036e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3046e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				printer.Process (fJPEGImage.fJPEGData [tileIndex]->Buffer      (),
3056e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim								 fJPEGImage.fJPEGData [tileIndex]->LogicalSize ());
3066e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3076e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				fDigests [tileIndex] = printer.Result ();
3086e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3096e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim				}
3106e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3116e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			}
3126e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3136e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	private:
3146e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3156e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		// Hidden copy constructor and assignment operator.
3166e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3176e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		dng_jpeg_image_find_digest_task (const dng_jpeg_image_find_digest_task &);
3186e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3196e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		dng_jpeg_image_find_digest_task & operator= (const dng_jpeg_image_find_digest_task &);
3206e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3216e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	};
3226e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3236e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim/*****************************************************************************/
3246e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3256e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimdng_fingerprint dng_jpeg_image::FindDigest (dng_host &host) const
3266e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	{
3276e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3286e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	uint32 tileCount = TileCount ();
3296e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3306e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	uint32 arrayCount = tileCount + (fJPEGTables.Get () ? 1 : 0);
3316e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3326e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	AutoArray<dng_fingerprint> digests (arrayCount);
3336e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3346e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	// Compute digest of each compressed tile.
3356e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3366e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		{
3376e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3386e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		uint32 threadCount = Min_uint32 (tileCount,
3396e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim										 host.PerformAreaTaskThreads ());
3406e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3416e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		dng_jpeg_image_find_digest_task task (*this,
3426e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim											  tileCount,
3436e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim											  digests.Get ());
3446e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3456e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		host.PerformAreaTask (task,
3466e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim							  dng_rect (0, 0, 16, 16 * threadCount));
3476e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3486e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		}
3496e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3506e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	// Compute digest of JPEG tables, if any.
3516e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3526e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	if (fJPEGTables.Get ())
3536e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		{
3546e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3556e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		dng_md5_printer printer;
3566e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3576e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		printer.Process (fJPEGTables->Buffer      (),
3586e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim						 fJPEGTables->LogicalSize ());
3596e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3606e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		digests [tileCount] = printer.Result ();
3616e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3626e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		}
3636e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3646e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	// Combine digests into a single digest.
3656e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3666e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		{
3676e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3686e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		dng_md5_printer printer;
3696e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3706e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		for (uint32 k = 0; k < arrayCount; k++)
3716e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			{
3726e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3736e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			printer.Process (digests [k].data,
3746e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim							 dng_fingerprint::kDNGFingerprintSize);
3756e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3766e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim			}
3776e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3786e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		return printer.Result ();
3796e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3806e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim		}
3816e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3826e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim	}
3836e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
3846e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim/*****************************************************************************/
3856e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim
386