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