blob: e520c89c7fc4398615620b4925c9430057e5d513 [file] [log] [blame]
yujieqin916de9f2016-01-25 08:26:16 -08001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkCodec.h"
9#include "SkCodecPriv.h"
Brian Osman10b81422017-12-14 10:27:21 -050010#include "SkColorSpacePriv.h"
Cary Clarka4083c92017-09-15 11:59:23 -040011#include "SkColorData.h"
yujieqin916de9f2016-01-25 08:26:16 -080012#include "SkData.h"
yujieqin916de9f2016-01-25 08:26:16 -080013#include "SkJpegCodec.h"
Mike Reedede7bac2017-07-23 15:30:02 -040014#include "SkMakeUnique.h"
yujieqinf236ee42016-02-29 07:14:42 -080015#include "SkMutex.h"
yujieqin916de9f2016-01-25 08:26:16 -080016#include "SkRawCodec.h"
17#include "SkRefCnt.h"
18#include "SkStream.h"
19#include "SkStreamPriv.h"
20#include "SkSwizzler.h"
yujieqinf236ee42016-02-29 07:14:42 -080021#include "SkTArray.h"
ebrauerb84b5b42016-01-27 08:21:03 -080022#include "SkTaskGroup.h"
yujieqin916de9f2016-01-25 08:26:16 -080023#include "SkTemplates.h"
24#include "SkTypes.h"
25
ebrauerb84b5b42016-01-27 08:21:03 -080026#include "dng_area_task.h"
yujieqin916de9f2016-01-25 08:26:16 -080027#include "dng_color_space.h"
yujieqinf236ee42016-02-29 07:14:42 -080028#include "dng_errors.h"
yujieqin916de9f2016-01-25 08:26:16 -080029#include "dng_exceptions.h"
30#include "dng_host.h"
31#include "dng_info.h"
32#include "dng_memory.h"
33#include "dng_render.h"
34#include "dng_stream.h"
35
36#include "src/piex.h"
37
38#include <cmath> // for std::round,floor,ceil
39#include <limits>
40
41namespace {
42
ebrauerb84b5b42016-01-27 08:21:03 -080043// Caluclates the number of tiles of tile_size that fit into the area in vertical and horizontal
44// directions.
45dng_point num_tiles_in_area(const dng_point &areaSize,
46 const dng_point_real64 &tileSize) {
47 // FIXME: Add a ceil_div() helper in SkCodecPriv.h
yujieqinfda27a92016-01-27 09:03:20 -080048 return dng_point(static_cast<int32>((areaSize.v + tileSize.v - 1) / tileSize.v),
49 static_cast<int32>((areaSize.h + tileSize.h - 1) / tileSize.h));
ebrauerb84b5b42016-01-27 08:21:03 -080050}
51
52int num_tasks_required(const dng_point& tilesInTask,
53 const dng_point& tilesInArea) {
54 return ((tilesInArea.v + tilesInTask.v - 1) / tilesInTask.v) *
55 ((tilesInArea.h + tilesInTask.h - 1) / tilesInTask.h);
56}
57
58// Calculate the number of tiles to process per task, taking into account the maximum number of
59// tasks. It prefers to increase horizontally for better locality of reference.
60dng_point num_tiles_per_task(const int maxTasks,
61 const dng_point &tilesInArea) {
62 dng_point tilesInTask = {1, 1};
63 while (num_tasks_required(tilesInTask, tilesInArea) > maxTasks) {
64 if (tilesInTask.h < tilesInArea.h) {
65 ++tilesInTask.h;
66 } else if (tilesInTask.v < tilesInArea.v) {
67 ++tilesInTask.v;
68 } else {
69 ThrowProgramError("num_tiles_per_task calculation is wrong.");
70 }
71 }
72 return tilesInTask;
73}
74
75std::vector<dng_rect> compute_task_areas(const int maxTasks, const dng_rect& area,
76 const dng_point& tileSize) {
77 std::vector<dng_rect> taskAreas;
78 const dng_point tilesInArea = num_tiles_in_area(area.Size(), tileSize);
79 const dng_point tilesPerTask = num_tiles_per_task(maxTasks, tilesInArea);
80 const dng_point taskAreaSize = {tilesPerTask.v * tileSize.v,
81 tilesPerTask.h * tileSize.h};
82 for (int v = 0; v < tilesInArea.v; v += tilesPerTask.v) {
83 for (int h = 0; h < tilesInArea.h; h += tilesPerTask.h) {
84 dng_rect taskArea;
85 taskArea.t = area.t + v * tileSize.v;
86 taskArea.l = area.l + h * tileSize.h;
87 taskArea.b = Min_int32(taskArea.t + taskAreaSize.v, area.b);
88 taskArea.r = Min_int32(taskArea.l + taskAreaSize.h, area.r);
89
90 taskAreas.push_back(taskArea);
91 }
92 }
93 return taskAreas;
94}
95
96class SkDngHost : public dng_host {
97public:
yujieqinfda27a92016-01-27 09:03:20 -080098 explicit SkDngHost(dng_memory_allocator* allocater) : dng_host(allocater) {}
ebrauerb84b5b42016-01-27 08:21:03 -080099
100 void PerformAreaTask(dng_area_task& task, const dng_rect& area) override {
ebrauerb84b5b42016-01-27 08:21:03 -0800101 SkTaskGroup taskGroup;
102
103 // tileSize is typically 256x256
104 const dng_point tileSize(task.FindTileSize(area));
Leon Scroggins III37819d02018-04-20 11:04:32 -0400105 const std::vector<dng_rect> taskAreas = compute_task_areas(this->PerformAreaTaskThreads(),
106 area, tileSize);
yujieqinfda27a92016-01-27 09:03:20 -0800107 const int numTasks = static_cast<int>(taskAreas.size());
ebrauerb84b5b42016-01-27 08:21:03 -0800108
yujieqinf236ee42016-02-29 07:14:42 -0800109 SkMutex mutex;
110 SkTArray<dng_exception> exceptions;
ebrauerb84b5b42016-01-27 08:21:03 -0800111 task.Start(numTasks, tileSize, &Allocator(), Sniffer());
112 for (int taskIndex = 0; taskIndex < numTasks; ++taskIndex) {
yujieqinf236ee42016-02-29 07:14:42 -0800113 taskGroup.add([&mutex, &exceptions, &task, this, taskIndex, taskAreas, tileSize] {
114 try {
115 task.ProcessOnThread(taskIndex, taskAreas[taskIndex], tileSize, this->Sniffer());
116 } catch (dng_exception& exception) {
117 SkAutoMutexAcquire lock(mutex);
118 exceptions.push_back(exception);
119 } catch (...) {
120 SkAutoMutexAcquire lock(mutex);
121 exceptions.push_back(dng_exception(dng_error_unknown));
122 }
ebrauerb84b5b42016-01-27 08:21:03 -0800123 });
124 }
125
126 taskGroup.wait();
127 task.Finish(numTasks);
yujieqinf236ee42016-02-29 07:14:42 -0800128
Leon Scroggins III37819d02018-04-20 11:04:32 -0400129 // We only re-throw the first exception.
yujieqinf236ee42016-02-29 07:14:42 -0800130 if (!exceptions.empty()) {
131 Throw_dng_error(exceptions.front().ErrorCode(), nullptr, nullptr);
132 }
ebrauerb84b5b42016-01-27 08:21:03 -0800133 }
134
135 uint32 PerformAreaTaskThreads() override {
Leon Scroggins III37819d02018-04-20 11:04:32 -0400136#ifdef SK_BUILD_FOR_ANDROID
Leon Scroggins III1530f392018-05-23 16:12:32 -0400137 // Only use 1 thread. DNGs with the warp effect require a lot of memory,
138 // and the amount of memory required scales linearly with the number of
139 // threads. The sample used in CTS requires over 500 MB, so even two
140 // threads is significantly expensive. There is no good way to tell
141 // whether the image has the warp effect.
142 return 1;
Leon Scroggins III37819d02018-04-20 11:04:32 -0400143#else
ebrauerb84b5b42016-01-27 08:21:03 -0800144 return kMaxMPThreads;
Leon Scroggins III37819d02018-04-20 11:04:32 -0400145#endif
ebrauerb84b5b42016-01-27 08:21:03 -0800146 }
147
148private:
149 typedef dng_host INHERITED;
150};
151
yujieqin916de9f2016-01-25 08:26:16 -0800152// T must be unsigned type.
153template <class T>
154bool safe_add_to_size_t(T arg1, T arg2, size_t* result) {
155 SkASSERT(arg1 >= 0);
156 SkASSERT(arg2 >= 0);
157 if (arg1 >= 0 && arg2 <= std::numeric_limits<T>::max() - arg1) {
158 T sum = arg1 + arg2;
159 if (sum <= std::numeric_limits<size_t>::max()) {
160 *result = static_cast<size_t>(sum);
161 return true;
162 }
163 }
164 return false;
165}
166
yujieqin9c7a8a42016-02-05 08:21:19 -0800167bool is_asset_stream(const SkStream& stream) {
168 return stream.hasLength() && stream.hasPosition();
169}
170
yujieqin916de9f2016-01-25 08:26:16 -0800171} // namespace
172
yujieqin9c7a8a42016-02-05 08:21:19 -0800173class SkRawStream {
yujieqin916de9f2016-01-25 08:26:16 -0800174public:
yujieqin9c7a8a42016-02-05 08:21:19 -0800175 virtual ~SkRawStream() {}
yujieqin916de9f2016-01-25 08:26:16 -0800176
Ben Wagner63fd7602017-10-09 15:45:33 -0400177 /*
yujieqin9c7a8a42016-02-05 08:21:19 -0800178 * Gets the length of the stream. Depending on the type of stream, this may require reading to
179 * the end of the stream.
180 */
181 virtual uint64 getLength() = 0;
182
183 virtual bool read(void* data, size_t offset, size_t length) = 0;
yujieqin916de9f2016-01-25 08:26:16 -0800184
185 /*
186 * Creates an SkMemoryStream from the offset with size.
187 * Note: for performance reason, this function is destructive to the SkRawStream. One should
188 * abandon current object after the function call.
189 */
Mike Reedede7bac2017-07-23 15:30:02 -0400190 virtual std::unique_ptr<SkMemoryStream> transferBuffer(size_t offset, size_t size) = 0;
yujieqin9c7a8a42016-02-05 08:21:19 -0800191};
192
yujieqinc04df212016-03-09 13:49:36 -0800193class SkRawLimitedDynamicMemoryWStream : public SkDynamicMemoryWStream {
194public:
Brian Salomond3b65972017-03-22 12:05:03 -0400195 ~SkRawLimitedDynamicMemoryWStream() override {}
yujieqinc04df212016-03-09 13:49:36 -0800196
197 bool write(const void* buffer, size_t size) override {
198 size_t newSize;
199 if (!safe_add_to_size_t(this->bytesWritten(), size, &newSize) ||
200 newSize > kMaxStreamSize)
201 {
202 SkCodecPrintf("Error: Stream size exceeds the limit.\n");
203 return false;
204 }
205 return this->INHERITED::write(buffer, size);
206 }
207
208private:
yujieqind6215cf2016-03-10 05:15:49 -0800209 // Most of valid RAW images will not be larger than 100MB. This limit is helpful to avoid
210 // streaming too large data chunk. We can always adjust the limit here if we need.
yujieqinc04df212016-03-09 13:49:36 -0800211 const size_t kMaxStreamSize = 100 * 1024 * 1024; // 100MB
212
213 typedef SkDynamicMemoryWStream INHERITED;
214};
215
216// Note: the maximum buffer size is 100MB (limited by SkRawLimitedDynamicMemoryWStream).
yujieqin9c7a8a42016-02-05 08:21:19 -0800217class SkRawBufferedStream : public SkRawStream {
218public:
Mike Reedede7bac2017-07-23 15:30:02 -0400219 explicit SkRawBufferedStream(std::unique_ptr<SkStream> stream)
220 : fStream(std::move(stream))
yujieqin9c7a8a42016-02-05 08:21:19 -0800221 , fWholeStreamRead(false)
222 {
223 // Only use SkRawBufferedStream when the stream is not an asset stream.
Mike Reedede7bac2017-07-23 15:30:02 -0400224 SkASSERT(!is_asset_stream(*fStream));
yujieqin9c7a8a42016-02-05 08:21:19 -0800225 }
226
227 ~SkRawBufferedStream() override {}
228
229 uint64 getLength() override {
230 if (!this->bufferMoreData(kReadToEnd)) { // read whole stream
231 ThrowReadFile();
232 }
233 return fStreamBuffer.bytesWritten();
234 }
235
236 bool read(void* data, size_t offset, size_t length) override {
237 if (length == 0) {
238 return true;
239 }
240
241 size_t sum;
242 if (!safe_add_to_size_t(offset, length, &sum)) {
243 return false;
244 }
245
246 return this->bufferMoreData(sum) && fStreamBuffer.read(data, offset, length);
247 }
248
Mike Reedede7bac2017-07-23 15:30:02 -0400249 std::unique_ptr<SkMemoryStream> transferBuffer(size_t offset, size_t size) override {
bungeman38d909e2016-08-02 14:40:46 -0700250 sk_sp<SkData> data(SkData::MakeUninitialized(size));
yujieqin916de9f2016-01-25 08:26:16 -0800251 if (offset > fStreamBuffer.bytesWritten()) {
252 // If the offset is not buffered, read from fStream directly and skip the buffering.
253 const size_t skipLength = offset - fStreamBuffer.bytesWritten();
254 if (fStream->skip(skipLength) != skipLength) {
255 return nullptr;
256 }
257 const size_t bytesRead = fStream->read(data->writable_data(), size);
258 if (bytesRead < size) {
bungeman38d909e2016-08-02 14:40:46 -0700259 data = SkData::MakeSubset(data.get(), 0, bytesRead);
yujieqin916de9f2016-01-25 08:26:16 -0800260 }
261 } else {
262 const size_t alreadyBuffered = SkTMin(fStreamBuffer.bytesWritten() - offset, size);
263 if (alreadyBuffered > 0 &&
264 !fStreamBuffer.read(data->writable_data(), offset, alreadyBuffered)) {
265 return nullptr;
266 }
267
268 const size_t remaining = size - alreadyBuffered;
269 if (remaining) {
270 auto* dst = static_cast<uint8_t*>(data->writable_data()) + alreadyBuffered;
271 const size_t bytesRead = fStream->read(dst, remaining);
272 size_t newSize;
273 if (bytesRead < remaining) {
274 if (!safe_add_to_size_t(alreadyBuffered, bytesRead, &newSize)) {
275 return nullptr;
276 }
bungeman38d909e2016-08-02 14:40:46 -0700277 data = SkData::MakeSubset(data.get(), 0, newSize);
yujieqin916de9f2016-01-25 08:26:16 -0800278 }
279 }
280 }
Mike Reed847068c2017-07-26 11:35:53 -0400281 return SkMemoryStream::Make(data);
yujieqin916de9f2016-01-25 08:26:16 -0800282 }
283
yujieqin916de9f2016-01-25 08:26:16 -0800284private:
285 // Note: if the newSize == kReadToEnd (0), this function will read to the end of stream.
286 bool bufferMoreData(size_t newSize) {
287 if (newSize == kReadToEnd) {
288 if (fWholeStreamRead) { // already read-to-end.
289 return true;
290 }
291
292 // TODO: optimize for the special case when the input is SkMemoryStream.
293 return SkStreamCopy(&fStreamBuffer, fStream.get());
294 }
295
296 if (newSize <= fStreamBuffer.bytesWritten()) { // already buffered to newSize
297 return true;
298 }
299 if (fWholeStreamRead) { // newSize is larger than the whole stream.
300 return false;
301 }
302
yujieqin22000d12016-02-02 08:09:07 -0800303 // Try to read at least 8192 bytes to avoid to many small reads.
304 const size_t kMinSizeToRead = 8192;
305 const size_t sizeRequested = newSize - fStreamBuffer.bytesWritten();
306 const size_t sizeToRead = SkTMax(kMinSizeToRead, sizeRequested);
307 SkAutoSTMalloc<kMinSizeToRead, uint8> tempBuffer(sizeToRead);
yujieqin916de9f2016-01-25 08:26:16 -0800308 const size_t bytesRead = fStream->read(tempBuffer.get(), sizeToRead);
yujieqin22000d12016-02-02 08:09:07 -0800309 if (bytesRead < sizeRequested) {
yujieqin916de9f2016-01-25 08:26:16 -0800310 return false;
311 }
312 return fStreamBuffer.write(tempBuffer.get(), bytesRead);
313 }
314
Ben Wagner145dbcd2016-11-03 14:40:50 -0400315 std::unique_ptr<SkStream> fStream;
yujieqin916de9f2016-01-25 08:26:16 -0800316 bool fWholeStreamRead;
317
yujieqinc04df212016-03-09 13:49:36 -0800318 // Use a size-limited stream to avoid holding too huge buffer.
319 SkRawLimitedDynamicMemoryWStream fStreamBuffer;
yujieqin916de9f2016-01-25 08:26:16 -0800320
321 const size_t kReadToEnd = 0;
322};
323
yujieqin9c7a8a42016-02-05 08:21:19 -0800324class SkRawAssetStream : public SkRawStream {
yujieqin916de9f2016-01-25 08:26:16 -0800325public:
Mike Reedede7bac2017-07-23 15:30:02 -0400326 explicit SkRawAssetStream(std::unique_ptr<SkStream> stream)
327 : fStream(std::move(stream))
yujieqin9c7a8a42016-02-05 08:21:19 -0800328 {
329 // Only use SkRawAssetStream when the stream is an asset stream.
Mike Reedede7bac2017-07-23 15:30:02 -0400330 SkASSERT(is_asset_stream(*fStream));
yujieqin9c7a8a42016-02-05 08:21:19 -0800331 }
yujieqin916de9f2016-01-25 08:26:16 -0800332
yujieqin9c7a8a42016-02-05 08:21:19 -0800333 ~SkRawAssetStream() override {}
yujieqin916de9f2016-01-25 08:26:16 -0800334
yujieqin9c7a8a42016-02-05 08:21:19 -0800335 uint64 getLength() override {
336 return fStream->getLength();
337 }
338
339
340 bool read(void* data, size_t offset, size_t length) override {
341 if (length == 0) {
342 return true;
343 }
344
345 size_t sum;
346 if (!safe_add_to_size_t(offset, length, &sum)) {
347 return false;
348 }
349
350 return fStream->seek(offset) && (fStream->read(data, length) == length);
351 }
352
Mike Reedede7bac2017-07-23 15:30:02 -0400353 std::unique_ptr<SkMemoryStream> transferBuffer(size_t offset, size_t size) override {
yujieqin9c7a8a42016-02-05 08:21:19 -0800354 if (fStream->getLength() < offset) {
355 return nullptr;
356 }
357
358 size_t sum;
359 if (!safe_add_to_size_t(offset, size, &sum)) {
360 return nullptr;
361 }
362
363 // This will allow read less than the requested "size", because the JPEG codec wants to
364 // handle also a partial JPEG file.
365 const size_t bytesToRead = SkTMin(sum, fStream->getLength()) - offset;
366 if (bytesToRead == 0) {
367 return nullptr;
368 }
369
370 if (fStream->getMemoryBase()) { // directly copy if getMemoryBase() is available.
bungeman38d909e2016-08-02 14:40:46 -0700371 sk_sp<SkData> data(SkData::MakeWithCopy(
yujieqin9c7a8a42016-02-05 08:21:19 -0800372 static_cast<const uint8_t*>(fStream->getMemoryBase()) + offset, bytesToRead));
mtklein852f15d2016-03-17 10:51:27 -0700373 fStream.reset();
Mike Reed847068c2017-07-26 11:35:53 -0400374 return SkMemoryStream::Make(data);
yujieqin9c7a8a42016-02-05 08:21:19 -0800375 } else {
bungeman38d909e2016-08-02 14:40:46 -0700376 sk_sp<SkData> data(SkData::MakeUninitialized(bytesToRead));
yujieqin9c7a8a42016-02-05 08:21:19 -0800377 if (!fStream->seek(offset)) {
378 return nullptr;
379 }
380 const size_t bytesRead = fStream->read(data->writable_data(), bytesToRead);
381 if (bytesRead < bytesToRead) {
bungeman38d909e2016-08-02 14:40:46 -0700382 data = SkData::MakeSubset(data.get(), 0, bytesRead);
yujieqin9c7a8a42016-02-05 08:21:19 -0800383 }
Mike Reed847068c2017-07-26 11:35:53 -0400384 return SkMemoryStream::Make(data);
yujieqin9c7a8a42016-02-05 08:21:19 -0800385 }
386 }
387private:
Ben Wagner145dbcd2016-11-03 14:40:50 -0400388 std::unique_ptr<SkStream> fStream;
yujieqin9c7a8a42016-02-05 08:21:19 -0800389};
390
391class SkPiexStream : public ::piex::StreamInterface {
392public:
393 // Will NOT take the ownership of the stream.
394 explicit SkPiexStream(SkRawStream* stream) : fStream(stream) {}
395
396 ~SkPiexStream() override {}
397
398 ::piex::Error GetData(const size_t offset, const size_t length,
399 uint8* data) override {
400 return fStream->read(static_cast<void*>(data), offset, length) ?
401 ::piex::Error::kOk : ::piex::Error::kFail;
yujieqin916de9f2016-01-25 08:26:16 -0800402 }
403
404private:
yujieqin9c7a8a42016-02-05 08:21:19 -0800405 SkRawStream* fStream;
406};
407
408class SkDngStream : public dng_stream {
409public:
410 // Will NOT take the ownership of the stream.
411 SkDngStream(SkRawStream* stream) : fStream(stream) {}
412
413 ~SkDngStream() override {}
414
415 uint64 DoGetLength() override { return fStream->getLength(); }
416
417 void DoRead(void* data, uint32 count, uint64 offset) override {
418 size_t sum;
419 if (!safe_add_to_size_t(static_cast<uint64>(count), offset, &sum) ||
420 !fStream->read(data, static_cast<size_t>(offset), static_cast<size_t>(count))) {
421 ThrowReadFile();
422 }
423 }
424
425private:
426 SkRawStream* fStream;
yujieqin916de9f2016-01-25 08:26:16 -0800427};
428
429class SkDngImage {
430public:
ebrauer46d2aa82016-02-17 08:04:00 -0800431 /*
432 * Initializes the object with the information from Piex in a first attempt. This way it can
433 * save time and storage to obtain the DNG dimensions and color filter array (CFA) pattern
434 * which is essential for the demosaicing of the sensor image.
435 * Note: this will take the ownership of the stream.
436 */
yujieqin916de9f2016-01-25 08:26:16 -0800437 static SkDngImage* NewFromStream(SkRawStream* stream) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400438 std::unique_ptr<SkDngImage> dngImage(new SkDngImage(stream));
Kevin Lubick2416f962018-02-12 08:26:39 -0500439#if defined(IS_FUZZING_WITH_LIBFUZZER)
440 // Libfuzzer easily runs out of memory after here. To avoid that
441 // We just pretend all streams are invalid. Our AFL-fuzzer
442 // should still exercise this code; it's more resistant to OOM.
443 return nullptr;
444#endif
Leon Scroggins III588fb042017-07-14 16:32:31 -0400445 if (!dngImage->initFromPiex() && !dngImage->readDng()) {
yujieqind6215cf2016-03-10 05:15:49 -0800446 return nullptr;
447 }
448
yujieqin916de9f2016-01-25 08:26:16 -0800449 return dngImage.release();
450 }
451
452 /*
453 * Renders the DNG image to the size. The DNG SDK only allows scaling close to integer factors
454 * down to 80 pixels on the short edge. The rendered image will be close to the specified size,
455 * but there is no guarantee that any of the edges will match the requested size. E.g.
456 * 100% size: 4000 x 3000
457 * requested size: 1600 x 1200
458 * returned size could be: 2000 x 1500
459 */
460 dng_image* render(int width, int height) {
461 if (!fHost || !fInfo || !fNegative || !fDngStream) {
462 if (!this->readDng()) {
463 return nullptr;
464 }
465 }
466
yujieqin916de9f2016-01-25 08:26:16 -0800467 // DNG SDK preserves the aspect ratio, so it only needs to know the longer dimension.
468 const int preferredSize = SkTMax(width, height);
469 try {
yujieqinf236ee42016-02-29 07:14:42 -0800470 // render() takes ownership of fHost, fInfo, fNegative and fDngStream when available.
Ben Wagner145dbcd2016-11-03 14:40:50 -0400471 std::unique_ptr<dng_host> host(fHost.release());
472 std::unique_ptr<dng_info> info(fInfo.release());
473 std::unique_ptr<dng_negative> negative(fNegative.release());
474 std::unique_ptr<dng_stream> dngStream(fDngStream.release());
yujieqinf236ee42016-02-29 07:14:42 -0800475
yujieqin916de9f2016-01-25 08:26:16 -0800476 host->SetPreferredSize(preferredSize);
477 host->ValidateSizes();
478
479 negative->ReadStage1Image(*host, *dngStream, *info);
480
481 if (info->fMaskIndex != -1) {
482 negative->ReadTransparencyMask(*host, *dngStream, *info);
483 }
484
485 negative->ValidateRawImageDigest(*host);
486 if (negative->IsDamaged()) {
487 return nullptr;
488 }
489
490 const int32 kMosaicPlane = -1;
491 negative->BuildStage2Image(*host);
492 negative->BuildStage3Image(*host, kMosaicPlane);
493
494 dng_render render(*host, *negative);
495 render.SetFinalSpace(dng_space_sRGB::Get());
496 render.SetFinalPixelType(ttByte);
497
498 dng_point stage3_size = negative->Stage3Image()->Size();
499 render.SetMaximumSize(SkTMax(stage3_size.h, stage3_size.v));
500
501 return render.Render();
502 } catch (...) {
503 return nullptr;
504 }
505 }
506
msarettc30c4182016-04-20 11:53:35 -0700507 int width() const {
508 return fWidth;
509 }
510
511 int height() const {
512 return fHeight;
yujieqin916de9f2016-01-25 08:26:16 -0800513 }
514
515 bool isScalable() const {
516 return fIsScalable;
517 }
518
519 bool isXtransImage() const {
520 return fIsXtransImage;
521 }
522
yujieqind6215cf2016-03-10 05:15:49 -0800523 // Quick check if the image contains a valid TIFF header as requested by DNG format.
Leon Scroggins III588fb042017-07-14 16:32:31 -0400524 // Does not affect ownership of stream.
525 static bool IsTiffHeaderValid(SkRawStream* stream) {
yujieqind6215cf2016-03-10 05:15:49 -0800526 const size_t kHeaderSize = 4;
Leon Scroggins III588fb042017-07-14 16:32:31 -0400527 unsigned char header[kHeaderSize];
528 if (!stream->read(header, 0 /* offset */, kHeaderSize)) {
yujieqind6215cf2016-03-10 05:15:49 -0800529 return false;
530 }
531
532 // Check if the header is valid (endian info and magic number "42").
msarett0e6274f2016-03-21 08:04:40 -0700533 bool littleEndian;
534 if (!is_valid_endian_marker(header, &littleEndian)) {
535 return false;
536 }
537
538 return 0x2A == get_endian_short(header + 2, littleEndian);
yujieqind6215cf2016-03-10 05:15:49 -0800539 }
540
Leon Scroggins III588fb042017-07-14 16:32:31 -0400541private:
Leon Scroggins IIId87fbee2016-12-02 16:47:53 -0500542 bool init(int width, int height, const dng_point& cfaPatternSize) {
msarettc30c4182016-04-20 11:53:35 -0700543 fWidth = width;
544 fHeight = height;
ebrauer46d2aa82016-02-17 08:04:00 -0800545
546 // The DNG SDK scales only during demosaicing, so scaling is only possible when
547 // a mosaic info is available.
548 fIsScalable = cfaPatternSize.v != 0 && cfaPatternSize.h != 0;
549 fIsXtransImage = fIsScalable ? (cfaPatternSize.v == 6 && cfaPatternSize.h == 6) : false;
Leon Scroggins IIId87fbee2016-12-02 16:47:53 -0500550
551 return width > 0 && height > 0;
ebrauer46d2aa82016-02-17 08:04:00 -0800552 }
553
554 bool initFromPiex() {
555 // Does not take the ownership of rawStream.
556 SkPiexStream piexStream(fStream.get());
557 ::piex::PreviewImageData imageData;
558 if (::piex::IsRaw(&piexStream)
559 && ::piex::GetPreviewImageData(&piexStream, &imageData) == ::piex::Error::kOk)
560 {
561 dng_point cfaPatternSize(imageData.cfa_pattern_dim[1], imageData.cfa_pattern_dim[0]);
Leon Scroggins IIId87fbee2016-12-02 16:47:53 -0500562 return this->init(static_cast<int>(imageData.full_width),
563 static_cast<int>(imageData.full_height), cfaPatternSize);
ebrauer46d2aa82016-02-17 08:04:00 -0800564 }
565 return false;
566 }
567
yujieqin916de9f2016-01-25 08:26:16 -0800568 bool readDng() {
yujieqin916de9f2016-01-25 08:26:16 -0800569 try {
yujieqinf236ee42016-02-29 07:14:42 -0800570 // Due to the limit of DNG SDK, we need to reset host and info.
571 fHost.reset(new SkDngHost(&fAllocator));
572 fInfo.reset(new dng_info);
Ben Wagner145dbcd2016-11-03 14:40:50 -0400573 fDngStream.reset(new SkDngStream(fStream.get()));
yujieqinf236ee42016-02-29 07:14:42 -0800574
yujieqin916de9f2016-01-25 08:26:16 -0800575 fHost->ValidateSizes();
576 fInfo->Parse(*fHost, *fDngStream);
577 fInfo->PostParse(*fHost);
578 if (!fInfo->IsValidDNG()) {
579 return false;
580 }
581
582 fNegative.reset(fHost->Make_dng_negative());
583 fNegative->Parse(*fHost, *fDngStream, *fInfo);
584 fNegative->PostParse(*fHost, *fDngStream, *fInfo);
585 fNegative->SynchronizeMetadata();
586
ebrauer46d2aa82016-02-17 08:04:00 -0800587 dng_point cfaPatternSize(0, 0);
588 if (fNegative->GetMosaicInfo() != nullptr) {
589 cfaPatternSize = fNegative->GetMosaicInfo()->fCFAPatternSize;
590 }
Leon Scroggins IIId87fbee2016-12-02 16:47:53 -0500591 return this->init(static_cast<int>(fNegative->DefaultCropSizeH().As_real64()),
592 static_cast<int>(fNegative->DefaultCropSizeV().As_real64()),
593 cfaPatternSize);
yujieqin916de9f2016-01-25 08:26:16 -0800594 } catch (...) {
yujieqin916de9f2016-01-25 08:26:16 -0800595 return false;
596 }
597 }
598
599 SkDngImage(SkRawStream* stream)
msarettac6c7502016-04-25 09:30:24 -0700600 : fStream(stream)
msarettac6c7502016-04-25 09:30:24 -0700601 {}
yujieqin916de9f2016-01-25 08:26:16 -0800602
Leon Scroggins IIIe7fd7ff2018-04-18 10:17:45 -0400603 dng_memory_allocator fAllocator;
Ben Wagner145dbcd2016-11-03 14:40:50 -0400604 std::unique_ptr<SkRawStream> fStream;
605 std::unique_ptr<dng_host> fHost;
606 std::unique_ptr<dng_info> fInfo;
607 std::unique_ptr<dng_negative> fNegative;
608 std::unique_ptr<dng_stream> fDngStream;
yujieqin916de9f2016-01-25 08:26:16 -0800609
msarettc30c4182016-04-20 11:53:35 -0700610 int fWidth;
611 int fHeight;
yujieqin916de9f2016-01-25 08:26:16 -0800612 bool fIsScalable;
613 bool fIsXtransImage;
614};
615
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400616static constexpr skcms_Matrix3x3 gAdobe_RGB_to_XYZD50 = {{
617 // ICC fixed-point (16.16) repesentation of:
618 // 0.60974, 0.20528, 0.14919,
619 // 0.31111, 0.62567, 0.06322,
620 // 0.01947, 0.06087, 0.74457,
621 { SkFixedToFloat(0x9c18), SkFixedToFloat(0x348d), SkFixedToFloat(0x2631) }, // Rx, Gx, Bx
622 { SkFixedToFloat(0x4fa5), SkFixedToFloat(0xa02c), SkFixedToFloat(0x102f) }, // Ry, Gy, By
623 { SkFixedToFloat(0x04fc), SkFixedToFloat(0x0f95), SkFixedToFloat(0xbe9c) }, // Rz, Gz, Bz
624}};
625
626
yujieqin916de9f2016-01-25 08:26:16 -0800627/*
628 * Tries to handle the image with PIEX. If PIEX returns kOk and finds the preview image, create a
629 * SkJpegCodec. If PIEX returns kFail, then the file is invalid, return nullptr. In other cases,
630 * fallback to create SkRawCodec for DNG images.
631 */
Mike Reedede7bac2017-07-23 15:30:02 -0400632std::unique_ptr<SkCodec> SkRawCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
633 Result* result) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400634 std::unique_ptr<SkRawStream> rawStream;
yujieqin9c7a8a42016-02-05 08:21:19 -0800635 if (is_asset_stream(*stream)) {
Mike Reedede7bac2017-07-23 15:30:02 -0400636 rawStream.reset(new SkRawAssetStream(std::move(stream)));
yujieqin9c7a8a42016-02-05 08:21:19 -0800637 } else {
Mike Reedede7bac2017-07-23 15:30:02 -0400638 rawStream.reset(new SkRawBufferedStream(std::move(stream)));
yujieqin9c7a8a42016-02-05 08:21:19 -0800639 }
640
641 // Does not take the ownership of rawStream.
642 SkPiexStream piexStream(rawStream.get());
yujieqin916de9f2016-01-25 08:26:16 -0800643 ::piex::PreviewImageData imageData;
yujieqin9c7a8a42016-02-05 08:21:19 -0800644 if (::piex::IsRaw(&piexStream)) {
645 ::piex::Error error = ::piex::GetPreviewImageData(&piexStream, &imageData);
Matt Sarettc5eabe72017-02-24 14:51:08 -0500646 if (error == ::piex::Error::kFail) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400647 *result = kInvalidInput;
Matt Sarettc5eabe72017-02-24 14:51:08 -0500648 return nullptr;
649 }
650
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400651 std::unique_ptr<SkEncodedInfo::ICCProfile> profile;
Leon Scroggins III5dd47e42018-09-27 15:26:48 -0400652 if (imageData.color_space == ::piex::PreviewImageData::kAdobeRgb) {
653 constexpr skcms_TransferFunction twoDotTwo =
654 { 2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
655 skcms_ICCProfile skcmsProfile;
656 skcms_Init(&skcmsProfile);
657 skcms_SetTransferFunction(&skcmsProfile, &twoDotTwo);
658 skcms_SetXYZD50(&skcmsProfile, &gAdobe_RGB_to_XYZD50);
659 profile = SkEncodedInfo::ICCProfile::Make(skcmsProfile);
Matt Sarettc5eabe72017-02-24 14:51:08 -0500660 }
yujieqin916de9f2016-01-25 08:26:16 -0800661
yujieqine34635d2016-04-14 07:04:00 -0700662 // Theoretically PIEX can return JPEG compressed image or uncompressed RGB image. We only
663 // handle the JPEG compressed preview image here.
664 if (error == ::piex::Error::kOk && imageData.preview.length > 0 &&
665 imageData.preview.format == ::piex::Image::kJpegCompressed)
666 {
yujieqin916de9f2016-01-25 08:26:16 -0800667 // transferBuffer() is destructive to the rawStream. Abandon the rawStream after this
668 // function call.
669 // FIXME: one may avoid the copy of memoryStream and use the buffered rawStream.
Mike Reedede7bac2017-07-23 15:30:02 -0400670 auto memoryStream = rawStream->transferBuffer(imageData.preview.offset,
671 imageData.preview.length);
Leon Scroggins III588fb042017-07-14 16:32:31 -0400672 if (!memoryStream) {
673 *result = kInvalidInput;
674 return nullptr;
675 }
Mike Reedede7bac2017-07-23 15:30:02 -0400676 return SkJpegCodec::MakeFromStream(std::move(memoryStream), result,
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400677 std::move(profile));
yujieqin916de9f2016-01-25 08:26:16 -0800678 }
679 }
680
Leon Scroggins III588fb042017-07-14 16:32:31 -0400681 if (!SkDngImage::IsTiffHeaderValid(rawStream.get())) {
682 *result = kUnimplemented;
683 return nullptr;
684 }
685
yujieqin9c7a8a42016-02-05 08:21:19 -0800686 // Takes the ownership of the rawStream.
Ben Wagner145dbcd2016-11-03 14:40:50 -0400687 std::unique_ptr<SkDngImage> dngImage(SkDngImage::NewFromStream(rawStream.release()));
yujieqin916de9f2016-01-25 08:26:16 -0800688 if (!dngImage) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400689 *result = kInvalidInput;
yujieqin916de9f2016-01-25 08:26:16 -0800690 return nullptr;
691 }
692
Leon Scroggins III588fb042017-07-14 16:32:31 -0400693 *result = kSuccess;
Mike Reedede7bac2017-07-23 15:30:02 -0400694 return std::unique_ptr<SkCodec>(new SkRawCodec(dngImage.release()));
yujieqin916de9f2016-01-25 08:26:16 -0800695}
696
Matt Saretta225e9b2016-11-07 10:26:17 -0500697SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
yujieqin916de9f2016-01-25 08:26:16 -0800698 size_t dstRowBytes, const Options& options,
yujieqin916de9f2016-01-25 08:26:16 -0800699 int* rowsDecoded) {
Matt Saretta225e9b2016-11-07 10:26:17 -0500700 SkImageInfo swizzlerInfo = dstInfo;
701 std::unique_ptr<uint32_t[]> xformBuffer = nullptr;
702 if (this->colorXform()) {
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400703 swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType);
Matt Saretta225e9b2016-11-07 10:26:17 -0500704 xformBuffer.reset(new uint32_t[dstInfo.width()]);
705 }
706
Ben Wagner145dbcd2016-11-03 14:40:50 -0400707 std::unique_ptr<SkSwizzler> swizzler(SkSwizzler::CreateSwizzler(
Matt Saretta225e9b2016-11-07 10:26:17 -0500708 this->getEncodedInfo(), nullptr, swizzlerInfo, options));
yujieqin916de9f2016-01-25 08:26:16 -0800709 SkASSERT(swizzler);
710
Matt Saretta225e9b2016-11-07 10:26:17 -0500711 const int width = dstInfo.width();
712 const int height = dstInfo.height();
Ben Wagner145dbcd2016-11-03 14:40:50 -0400713 std::unique_ptr<dng_image> image(fDngImage->render(width, height));
yujieqin916de9f2016-01-25 08:26:16 -0800714 if (!image) {
715 return kInvalidInput;
716 }
717
718 // Because the DNG SDK can not guarantee to render to requested size, we allow a small
719 // difference. Only the overlapping region will be converted.
720 const float maxDiffRatio = 1.03f;
721 const dng_point& imageSize = image->Size();
Matt Sarette18c97b2016-11-28 18:46:37 -0500722 if (imageSize.h / (float) width > maxDiffRatio || imageSize.h < width ||
723 imageSize.v / (float) height > maxDiffRatio || imageSize.v < height) {
yujieqin916de9f2016-01-25 08:26:16 -0800724 return SkCodec::kInvalidScale;
725 }
726
727 void* dstRow = dst;
yujieqin24716be2016-01-27 07:59:00 -0800728 SkAutoTMalloc<uint8_t> srcRow(width * 3);
yujieqin916de9f2016-01-25 08:26:16 -0800729
730 dng_pixel_buffer buffer;
731 buffer.fData = &srcRow[0];
732 buffer.fPlane = 0;
733 buffer.fPlanes = 3;
734 buffer.fColStep = buffer.fPlanes;
735 buffer.fPlaneStep = 1;
736 buffer.fPixelType = ttByte;
737 buffer.fPixelSize = sizeof(uint8_t);
scroggoe6459652016-01-30 10:06:11 -0800738 buffer.fRowStep = width * 3;
yujieqin916de9f2016-01-25 08:26:16 -0800739
740 for (int i = 0; i < height; ++i) {
741 buffer.fArea = dng_rect(i, 0, i + 1, width);
742
743 try {
744 image->Get(buffer, dng_image::edge_zero);
745 } catch (...) {
746 *rowsDecoded = i;
nagarajan.nf398dd52017-09-19 17:46:52 +0530747 return kIncompleteInput;
yujieqin916de9f2016-01-25 08:26:16 -0800748 }
749
Matt Saretta225e9b2016-11-07 10:26:17 -0500750 if (this->colorXform()) {
751 swizzler->swizzle(xformBuffer.get(), &srcRow[0]);
752
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400753 this->applyColorXform(dstRow, xformBuffer.get(), dstInfo.width());
Matt Saretta225e9b2016-11-07 10:26:17 -0500754 } else {
755 swizzler->swizzle(dstRow, &srcRow[0]);
Matt Saretta225e9b2016-11-07 10:26:17 -0500756 }
nagarajan.nf398dd52017-09-19 17:46:52 +0530757 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
yujieqin916de9f2016-01-25 08:26:16 -0800758 }
759 return kSuccess;
760}
761
762SkISize SkRawCodec::onGetScaledDimensions(float desiredScale) const {
763 SkASSERT(desiredScale <= 1.f);
yujieqind0e08852016-03-03 07:38:27 -0800764
Leon Scroggins III712476e2018-10-03 15:47:00 -0400765 const SkISize dim = this->dimensions();
yujieqind0e08852016-03-03 07:38:27 -0800766 SkASSERT(dim.fWidth != 0 && dim.fHeight != 0);
767
yujieqin916de9f2016-01-25 08:26:16 -0800768 if (!fDngImage->isScalable()) {
769 return dim;
770 }
771
772 // Limits the minimum size to be 80 on the short edge.
yujieqin076d83d2016-01-27 08:25:53 -0800773 const float shortEdge = static_cast<float>(SkTMin(dim.fWidth, dim.fHeight));
yujieqin916de9f2016-01-25 08:26:16 -0800774 if (desiredScale < 80.f / shortEdge) {
775 desiredScale = 80.f / shortEdge;
776 }
777
778 // For Xtrans images, the integer-factor scaling does not support the half-size scaling case
779 // (stronger downscalings are fine). In this case, returns the factor "3" scaling instead.
780 if (fDngImage->isXtransImage() && desiredScale > 1.f / 3.f && desiredScale < 1.f) {
781 desiredScale = 1.f / 3.f;
782 }
783
784 // Round to integer-factors.
785 const float finalScale = std::floor(1.f/ desiredScale);
yujieqin076d83d2016-01-27 08:25:53 -0800786 return SkISize::Make(static_cast<int32_t>(std::floor(dim.fWidth / finalScale)),
787 static_cast<int32_t>(std::floor(dim.fHeight / finalScale)));
yujieqin916de9f2016-01-25 08:26:16 -0800788}
789
790bool SkRawCodec::onDimensionsSupported(const SkISize& dim) {
Leon Scroggins III712476e2018-10-03 15:47:00 -0400791 const SkISize fullDim = this->dimensions();
yujieqin076d83d2016-01-27 08:25:53 -0800792 const float fullShortEdge = static_cast<float>(SkTMin(fullDim.fWidth, fullDim.fHeight));
793 const float shortEdge = static_cast<float>(SkTMin(dim.fWidth, dim.fHeight));
yujieqin916de9f2016-01-25 08:26:16 -0800794
795 SkISize sizeFloor = this->onGetScaledDimensions(1.f / std::floor(fullShortEdge / shortEdge));
796 SkISize sizeCeil = this->onGetScaledDimensions(1.f / std::ceil(fullShortEdge / shortEdge));
797 return sizeFloor == dim || sizeCeil == dim;
798}
799
800SkRawCodec::~SkRawCodec() {}
801
802SkRawCodec::SkRawCodec(SkDngImage* dngImage)
Leon Scroggins III5dd47e42018-09-27 15:26:48 -0400803 : INHERITED(SkEncodedInfo::Make(dngImage->width(), dngImage->height(),
804 SkEncodedInfo::kRGB_Color,
805 SkEncodedInfo::kOpaque_Alpha, 8),
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400806 skcms_PixelFormat_RGBA_8888, nullptr)
yujieqin916de9f2016-01-25 08:26:16 -0800807 , fDngImage(dngImage) {}