/src/skia/third_party/externals/dng_sdk/source/dng_jpeg_image.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 0 | { |
40 | | |
41 | 0 | } |
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 | 0 | { |
85 | | |
86 | 0 | fMinTaskArea = 16 * 16; |
87 | 0 | fUnitCell = dng_point (16, 16); |
88 | 0 | fMaxTileSize = dng_point (16, 16); |
89 | | |
90 | 0 | } |
91 | | |
92 | | void Process (uint32 /* threadIndex */, |
93 | | const dng_rect & /* tile */, |
94 | | dng_abort_sniffer *sniffer) |
95 | 0 | { |
96 | | |
97 | 0 | AutoPtr<dng_memory_block> compressedBuffer; |
98 | 0 | AutoPtr<dng_memory_block> uncompressedBuffer; |
99 | 0 | AutoPtr<dng_memory_block> subTileBlockBuffer; |
100 | 0 | AutoPtr<dng_memory_block> tempBuffer; |
101 | | |
102 | 0 | uint32 uncompressedSize = SafeUint32Mult ( |
103 | 0 | fIFD.fTileLength, fIFD.fTileWidth, fIFD.fSamplesPerPixel); |
104 | | |
105 | 0 | uncompressedBuffer.Reset (fHost.Allocate (uncompressedSize)); |
106 | | |
107 | 0 | uint32 tilesAcross = fIFD.TilesAcross (); |
108 | | |
109 | 0 | while (true) |
110 | 0 | { |
111 | | |
112 | 0 | uint32 tileIndex; |
113 | | |
114 | 0 | { |
115 | | |
116 | 0 | dng_lock_mutex lock (&fMutex); |
117 | | |
118 | 0 | if (fNextTileIndex == fTileCount) |
119 | 0 | { |
120 | 0 | return; |
121 | 0 | } |
122 | | |
123 | 0 | tileIndex = fNextTileIndex++; |
124 | | |
125 | 0 | } |
126 | | |
127 | 0 | dng_abort_sniffer::SniffForAbort (sniffer); |
128 | | |
129 | 0 | uint32 rowIndex = tileIndex / tilesAcross; |
130 | 0 | uint32 colIndex = tileIndex % tilesAcross; |
131 | | |
132 | 0 | dng_rect tileArea = fIFD.TileArea (rowIndex, colIndex); |
133 | | |
134 | 0 | dng_memory_stream stream (fHost.Allocator ()); |
135 | | |
136 | 0 | fWriter.WriteTile (fHost, |
137 | 0 | fIFD, |
138 | 0 | stream, |
139 | 0 | fImage, |
140 | 0 | tileArea, |
141 | 0 | 1, |
142 | 0 | compressedBuffer, |
143 | 0 | uncompressedBuffer, |
144 | 0 | subTileBlockBuffer, |
145 | 0 | tempBuffer); |
146 | | |
147 | 0 | fJPEGImage.fJPEGData [tileIndex].Reset (stream.AsMemoryBlock (fHost.Allocator ())); |
148 | | |
149 | 0 | } |
150 | | |
151 | 0 | } |
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 | 0 | { |
170 | | |
171 | | #if qDNGValidate |
172 | | dng_timer timer ("Encode JPEG Proxy time"); |
173 | | #endif |
174 | | |
175 | 0 | DNG_ASSERT (image.PixelType () == ttByte, "Cannot JPEG encode non-byte image"); |
176 | | |
177 | 0 | fImageSize = image.Bounds ().Size (); |
178 | | |
179 | 0 | dng_ifd ifd; |
180 | | |
181 | 0 | ifd.fImageWidth = fImageSize.h; |
182 | 0 | ifd.fImageLength = fImageSize.v; |
183 | | |
184 | 0 | ifd.fSamplesPerPixel = image.Planes (); |
185 | | |
186 | 0 | ifd.fBitsPerSample [0] = 8; |
187 | 0 | ifd.fBitsPerSample [1] = 8; |
188 | 0 | ifd.fBitsPerSample [2] = 8; |
189 | 0 | ifd.fBitsPerSample [3] = 8; |
190 | | |
191 | 0 | ifd.fPhotometricInterpretation = piLinearRaw; |
192 | | |
193 | 0 | ifd.fCompression = ccLossyJPEG; |
194 | | |
195 | 0 | ifd.FindTileSize (512 * 512 * ifd.fSamplesPerPixel); |
196 | | |
197 | 0 | fTileSize.h = ifd.fTileWidth; |
198 | 0 | 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 | 0 | bool useHigherQuality = (uint64) ifd.fImageWidth * |
206 | 0 | (uint64) ifd.fImageLength > 5000000 || |
207 | 0 | image.Bounds ().Size () == negative.OriginalDefaultFinalSize (); |
208 | | |
209 | 0 | if (negative.ColorimetricReference () == crSceneReferred) |
210 | 0 | { |
211 | 0 | ifd.fCompressionQuality = useHigherQuality ? 11 : 10; |
212 | 0 | } |
213 | 0 | else |
214 | 0 | { |
215 | 0 | ifd.fCompressionQuality = useHigherQuality ? 10 : 8; |
216 | 0 | } |
217 | | |
218 | 0 | uint32 tilesAcross = ifd.TilesAcross (); |
219 | 0 | uint32 tilesDown = ifd.TilesDown (); |
220 | | |
221 | 0 | uint32 tileCount = tilesAcross * tilesDown; |
222 | | |
223 | 0 | fJPEGData.Reset (tileCount); |
224 | | |
225 | 0 | uint32 threadCount = Min_uint32 (tileCount, |
226 | 0 | host.PerformAreaTaskThreads ()); |
227 | | |
228 | 0 | dng_jpeg_image_encode_task task (host, |
229 | 0 | writer, |
230 | 0 | image, |
231 | 0 | *this, |
232 | 0 | tileCount, |
233 | 0 | ifd); |
234 | | |
235 | 0 | host.PerformAreaTask (task, |
236 | 0 | dng_rect (0, 0, 16, 16 * threadCount)); |
237 | | |
238 | 0 | } |
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 | 0 | { |
270 | | |
271 | 0 | fMinTaskArea = 16 * 16; |
272 | 0 | fUnitCell = dng_point (16, 16); |
273 | 0 | fMaxTileSize = dng_point (16, 16); |
274 | | |
275 | 0 | } |
276 | | |
277 | | void Process (uint32 /* threadIndex */, |
278 | | const dng_rect & /* tile */, |
279 | | dng_abort_sniffer *sniffer) |
280 | 0 | { |
281 | | |
282 | 0 | while (true) |
283 | 0 | { |
284 | | |
285 | 0 | uint32 tileIndex; |
286 | | |
287 | 0 | { |
288 | | |
289 | 0 | dng_lock_mutex lock (&fMutex); |
290 | | |
291 | 0 | if (fNextTileIndex == fTileCount) |
292 | 0 | { |
293 | 0 | return; |
294 | 0 | } |
295 | | |
296 | 0 | tileIndex = fNextTileIndex++; |
297 | | |
298 | 0 | } |
299 | | |
300 | 0 | dng_abort_sniffer::SniffForAbort (sniffer); |
301 | | |
302 | 0 | dng_md5_printer printer; |
303 | | |
304 | 0 | printer.Process (fJPEGImage.fJPEGData [tileIndex]->Buffer (), |
305 | 0 | fJPEGImage.fJPEGData [tileIndex]->LogicalSize ()); |
306 | | |
307 | 0 | fDigests [tileIndex] = printer.Result (); |
308 | | |
309 | 0 | } |
310 | | |
311 | 0 | } |
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 | 0 | { |
327 | | |
328 | 0 | uint32 tileCount = TileCount (); |
329 | | |
330 | 0 | uint32 arrayCount = tileCount + (fJPEGTables.Get () ? 1 : 0); |
331 | | |
332 | 0 | AutoArray<dng_fingerprint> digests (arrayCount); |
333 | | |
334 | | // Compute digest of each compressed tile. |
335 | |
|
336 | 0 | { |
337 | | |
338 | 0 | uint32 threadCount = Min_uint32 (tileCount, |
339 | 0 | host.PerformAreaTaskThreads ()); |
340 | | |
341 | 0 | dng_jpeg_image_find_digest_task task (*this, |
342 | 0 | tileCount, |
343 | 0 | digests.Get ()); |
344 | | |
345 | 0 | host.PerformAreaTask (task, |
346 | 0 | dng_rect (0, 0, 16, 16 * threadCount)); |
347 | | |
348 | 0 | } |
349 | | |
350 | | // Compute digest of JPEG tables, if any. |
351 | | |
352 | 0 | if (fJPEGTables.Get ()) |
353 | 0 | { |
354 | | |
355 | 0 | dng_md5_printer printer; |
356 | | |
357 | 0 | printer.Process (fJPEGTables->Buffer (), |
358 | 0 | fJPEGTables->LogicalSize ()); |
359 | | |
360 | 0 | digests [tileCount] = printer.Result (); |
361 | | |
362 | 0 | } |
363 | | |
364 | | // Combine digests into a single digest. |
365 | | |
366 | 0 | { |
367 | | |
368 | 0 | dng_md5_printer printer; |
369 | | |
370 | 0 | for (uint32 k = 0; k < arrayCount; k++) |
371 | 0 | { |
372 | | |
373 | 0 | printer.Process (digests [k].data, |
374 | 0 | dng_fingerprint::kDNGFingerprintSize); |
375 | | |
376 | 0 | } |
377 | | |
378 | 0 | return printer.Result (); |
379 | | |
380 | 0 | } |
381 | | |
382 | 0 | } |
383 | | |
384 | | /*****************************************************************************/ |
385 | | |