blob: 9eea78cf4ba2dd12bd00030c41a423eb609d36e4 [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
Leon Scroggins III33d53942018-08-22 16:46:32 -0400507 const SkEncodedInfo& getEncodedInfo() const {
508 return fEncodedInfo;
509 }
510
msarettc30c4182016-04-20 11:53:35 -0700511 int width() const {
512 return fWidth;
513 }
514
515 int height() const {
516 return fHeight;
yujieqin916de9f2016-01-25 08:26:16 -0800517 }
518
519 bool isScalable() const {
520 return fIsScalable;
521 }
522
523 bool isXtransImage() const {
524 return fIsXtransImage;
525 }
526
yujieqind6215cf2016-03-10 05:15:49 -0800527 // Quick check if the image contains a valid TIFF header as requested by DNG format.
Leon Scroggins III588fb042017-07-14 16:32:31 -0400528 // Does not affect ownership of stream.
529 static bool IsTiffHeaderValid(SkRawStream* stream) {
yujieqind6215cf2016-03-10 05:15:49 -0800530 const size_t kHeaderSize = 4;
Leon Scroggins III588fb042017-07-14 16:32:31 -0400531 unsigned char header[kHeaderSize];
532 if (!stream->read(header, 0 /* offset */, kHeaderSize)) {
yujieqind6215cf2016-03-10 05:15:49 -0800533 return false;
534 }
535
536 // Check if the header is valid (endian info and magic number "42").
msarett0e6274f2016-03-21 08:04:40 -0700537 bool littleEndian;
538 if (!is_valid_endian_marker(header, &littleEndian)) {
539 return false;
540 }
541
542 return 0x2A == get_endian_short(header + 2, littleEndian);
yujieqind6215cf2016-03-10 05:15:49 -0800543 }
544
Leon Scroggins III588fb042017-07-14 16:32:31 -0400545private:
Leon Scroggins IIId87fbee2016-12-02 16:47:53 -0500546 bool init(int width, int height, const dng_point& cfaPatternSize) {
msarettc30c4182016-04-20 11:53:35 -0700547 fWidth = width;
548 fHeight = height;
ebrauer46d2aa82016-02-17 08:04:00 -0800549
550 // The DNG SDK scales only during demosaicing, so scaling is only possible when
551 // a mosaic info is available.
552 fIsScalable = cfaPatternSize.v != 0 && cfaPatternSize.h != 0;
553 fIsXtransImage = fIsScalable ? (cfaPatternSize.v == 6 && cfaPatternSize.h == 6) : false;
Leon Scroggins IIId87fbee2016-12-02 16:47:53 -0500554
555 return width > 0 && height > 0;
ebrauer46d2aa82016-02-17 08:04:00 -0800556 }
557
558 bool initFromPiex() {
559 // Does not take the ownership of rawStream.
560 SkPiexStream piexStream(fStream.get());
561 ::piex::PreviewImageData imageData;
562 if (::piex::IsRaw(&piexStream)
563 && ::piex::GetPreviewImageData(&piexStream, &imageData) == ::piex::Error::kOk)
564 {
565 dng_point cfaPatternSize(imageData.cfa_pattern_dim[1], imageData.cfa_pattern_dim[0]);
Leon Scroggins IIId87fbee2016-12-02 16:47:53 -0500566 return this->init(static_cast<int>(imageData.full_width),
567 static_cast<int>(imageData.full_height), cfaPatternSize);
ebrauer46d2aa82016-02-17 08:04:00 -0800568 }
569 return false;
570 }
571
yujieqin916de9f2016-01-25 08:26:16 -0800572 bool readDng() {
yujieqin916de9f2016-01-25 08:26:16 -0800573 try {
yujieqinf236ee42016-02-29 07:14:42 -0800574 // Due to the limit of DNG SDK, we need to reset host and info.
575 fHost.reset(new SkDngHost(&fAllocator));
576 fInfo.reset(new dng_info);
Ben Wagner145dbcd2016-11-03 14:40:50 -0400577 fDngStream.reset(new SkDngStream(fStream.get()));
yujieqinf236ee42016-02-29 07:14:42 -0800578
yujieqin916de9f2016-01-25 08:26:16 -0800579 fHost->ValidateSizes();
580 fInfo->Parse(*fHost, *fDngStream);
581 fInfo->PostParse(*fHost);
582 if (!fInfo->IsValidDNG()) {
583 return false;
584 }
585
586 fNegative.reset(fHost->Make_dng_negative());
587 fNegative->Parse(*fHost, *fDngStream, *fInfo);
588 fNegative->PostParse(*fHost, *fDngStream, *fInfo);
589 fNegative->SynchronizeMetadata();
590
ebrauer46d2aa82016-02-17 08:04:00 -0800591 dng_point cfaPatternSize(0, 0);
592 if (fNegative->GetMosaicInfo() != nullptr) {
593 cfaPatternSize = fNegative->GetMosaicInfo()->fCFAPatternSize;
594 }
Leon Scroggins IIId87fbee2016-12-02 16:47:53 -0500595 return this->init(static_cast<int>(fNegative->DefaultCropSizeH().As_real64()),
596 static_cast<int>(fNegative->DefaultCropSizeV().As_real64()),
597 cfaPatternSize);
yujieqin916de9f2016-01-25 08:26:16 -0800598 } catch (...) {
yujieqin916de9f2016-01-25 08:26:16 -0800599 return false;
600 }
601 }
602
603 SkDngImage(SkRawStream* stream)
msarettac6c7502016-04-25 09:30:24 -0700604 : fStream(stream)
Leon Scroggins III33d53942018-08-22 16:46:32 -0400605 , fEncodedInfo(SkEncodedInfo::Make(SkEncodedInfo::kRGB_Color,
606 SkEncodedInfo::kOpaque_Alpha, 8))
msarettac6c7502016-04-25 09:30:24 -0700607 {}
yujieqin916de9f2016-01-25 08:26:16 -0800608
Leon Scroggins IIIe7fd7ff2018-04-18 10:17:45 -0400609 dng_memory_allocator fAllocator;
Ben Wagner145dbcd2016-11-03 14:40:50 -0400610 std::unique_ptr<SkRawStream> fStream;
611 std::unique_ptr<dng_host> fHost;
612 std::unique_ptr<dng_info> fInfo;
613 std::unique_ptr<dng_negative> fNegative;
614 std::unique_ptr<dng_stream> fDngStream;
yujieqin916de9f2016-01-25 08:26:16 -0800615
msarettc30c4182016-04-20 11:53:35 -0700616 int fWidth;
617 int fHeight;
Leon Scroggins III33d53942018-08-22 16:46:32 -0400618 SkEncodedInfo fEncodedInfo;
yujieqin916de9f2016-01-25 08:26:16 -0800619 bool fIsScalable;
620 bool fIsXtransImage;
621};
622
623/*
624 * Tries to handle the image with PIEX. If PIEX returns kOk and finds the preview image, create a
625 * SkJpegCodec. If PIEX returns kFail, then the file is invalid, return nullptr. In other cases,
626 * fallback to create SkRawCodec for DNG images.
627 */
Mike Reedede7bac2017-07-23 15:30:02 -0400628std::unique_ptr<SkCodec> SkRawCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
629 Result* result) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400630 std::unique_ptr<SkRawStream> rawStream;
yujieqin9c7a8a42016-02-05 08:21:19 -0800631 if (is_asset_stream(*stream)) {
Mike Reedede7bac2017-07-23 15:30:02 -0400632 rawStream.reset(new SkRawAssetStream(std::move(stream)));
yujieqin9c7a8a42016-02-05 08:21:19 -0800633 } else {
Mike Reedede7bac2017-07-23 15:30:02 -0400634 rawStream.reset(new SkRawBufferedStream(std::move(stream)));
yujieqin9c7a8a42016-02-05 08:21:19 -0800635 }
636
637 // Does not take the ownership of rawStream.
638 SkPiexStream piexStream(rawStream.get());
yujieqin916de9f2016-01-25 08:26:16 -0800639 ::piex::PreviewImageData imageData;
yujieqin9c7a8a42016-02-05 08:21:19 -0800640 if (::piex::IsRaw(&piexStream)) {
641 ::piex::Error error = ::piex::GetPreviewImageData(&piexStream, &imageData);
Matt Sarettc5eabe72017-02-24 14:51:08 -0500642 if (error == ::piex::Error::kFail) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400643 *result = kInvalidInput;
Matt Sarettc5eabe72017-02-24 14:51:08 -0500644 return nullptr;
645 }
646
Leon Scroggins III33d53942018-08-22 16:46:32 -0400647 sk_sp<SkColorSpace> colorSpace;
Matt Sarettc5eabe72017-02-24 14:51:08 -0500648 switch (imageData.color_space) {
649 case ::piex::PreviewImageData::kSrgb:
Leon Scroggins III33d53942018-08-22 16:46:32 -0400650 colorSpace = SkColorSpace::MakeSRGB();
Matt Sarettc5eabe72017-02-24 14:51:08 -0500651 break;
Leon Scroggins III33d53942018-08-22 16:46:32 -0400652 case ::piex::PreviewImageData::kAdobeRgb:
653 colorSpace = SkColorSpace::MakeRGB(g2Dot2_TransferFn,
654 SkColorSpace::kAdobeRGB_Gamut);
Matt Sarettc5eabe72017-02-24 14:51:08 -0500655 break;
656 }
yujieqin916de9f2016-01-25 08:26:16 -0800657
yujieqine34635d2016-04-14 07:04:00 -0700658 // Theoretically PIEX can return JPEG compressed image or uncompressed RGB image. We only
659 // handle the JPEG compressed preview image here.
660 if (error == ::piex::Error::kOk && imageData.preview.length > 0 &&
661 imageData.preview.format == ::piex::Image::kJpegCompressed)
662 {
yujieqin916de9f2016-01-25 08:26:16 -0800663 // transferBuffer() is destructive to the rawStream. Abandon the rawStream after this
664 // function call.
665 // FIXME: one may avoid the copy of memoryStream and use the buffered rawStream.
Mike Reedede7bac2017-07-23 15:30:02 -0400666 auto memoryStream = rawStream->transferBuffer(imageData.preview.offset,
667 imageData.preview.length);
Leon Scroggins III588fb042017-07-14 16:32:31 -0400668 if (!memoryStream) {
669 *result = kInvalidInput;
670 return nullptr;
671 }
Mike Reedede7bac2017-07-23 15:30:02 -0400672 return SkJpegCodec::MakeFromStream(std::move(memoryStream), result,
Leon Scroggins III33d53942018-08-22 16:46:32 -0400673 std::move(colorSpace));
yujieqin916de9f2016-01-25 08:26:16 -0800674 }
675 }
676
Leon Scroggins III588fb042017-07-14 16:32:31 -0400677 if (!SkDngImage::IsTiffHeaderValid(rawStream.get())) {
678 *result = kUnimplemented;
679 return nullptr;
680 }
681
yujieqin9c7a8a42016-02-05 08:21:19 -0800682 // Takes the ownership of the rawStream.
Ben Wagner145dbcd2016-11-03 14:40:50 -0400683 std::unique_ptr<SkDngImage> dngImage(SkDngImage::NewFromStream(rawStream.release()));
yujieqin916de9f2016-01-25 08:26:16 -0800684 if (!dngImage) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400685 *result = kInvalidInput;
yujieqin916de9f2016-01-25 08:26:16 -0800686 return nullptr;
687 }
688
Leon Scroggins III588fb042017-07-14 16:32:31 -0400689 *result = kSuccess;
Mike Reedede7bac2017-07-23 15:30:02 -0400690 return std::unique_ptr<SkCodec>(new SkRawCodec(dngImage.release()));
yujieqin916de9f2016-01-25 08:26:16 -0800691}
692
Matt Saretta225e9b2016-11-07 10:26:17 -0500693SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
yujieqin916de9f2016-01-25 08:26:16 -0800694 size_t dstRowBytes, const Options& options,
yujieqin916de9f2016-01-25 08:26:16 -0800695 int* rowsDecoded) {
Matt Saretta225e9b2016-11-07 10:26:17 -0500696 SkImageInfo swizzlerInfo = dstInfo;
697 std::unique_ptr<uint32_t[]> xformBuffer = nullptr;
698 if (this->colorXform()) {
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400699 swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType);
Matt Saretta225e9b2016-11-07 10:26:17 -0500700 xformBuffer.reset(new uint32_t[dstInfo.width()]);
701 }
702
Ben Wagner145dbcd2016-11-03 14:40:50 -0400703 std::unique_ptr<SkSwizzler> swizzler(SkSwizzler::CreateSwizzler(
Matt Saretta225e9b2016-11-07 10:26:17 -0500704 this->getEncodedInfo(), nullptr, swizzlerInfo, options));
yujieqin916de9f2016-01-25 08:26:16 -0800705 SkASSERT(swizzler);
706
Matt Saretta225e9b2016-11-07 10:26:17 -0500707 const int width = dstInfo.width();
708 const int height = dstInfo.height();
Ben Wagner145dbcd2016-11-03 14:40:50 -0400709 std::unique_ptr<dng_image> image(fDngImage->render(width, height));
yujieqin916de9f2016-01-25 08:26:16 -0800710 if (!image) {
711 return kInvalidInput;
712 }
713
714 // Because the DNG SDK can not guarantee to render to requested size, we allow a small
715 // difference. Only the overlapping region will be converted.
716 const float maxDiffRatio = 1.03f;
717 const dng_point& imageSize = image->Size();
Matt Sarette18c97b2016-11-28 18:46:37 -0500718 if (imageSize.h / (float) width > maxDiffRatio || imageSize.h < width ||
719 imageSize.v / (float) height > maxDiffRatio || imageSize.v < height) {
yujieqin916de9f2016-01-25 08:26:16 -0800720 return SkCodec::kInvalidScale;
721 }
722
723 void* dstRow = dst;
yujieqin24716be2016-01-27 07:59:00 -0800724 SkAutoTMalloc<uint8_t> srcRow(width * 3);
yujieqin916de9f2016-01-25 08:26:16 -0800725
726 dng_pixel_buffer buffer;
727 buffer.fData = &srcRow[0];
728 buffer.fPlane = 0;
729 buffer.fPlanes = 3;
730 buffer.fColStep = buffer.fPlanes;
731 buffer.fPlaneStep = 1;
732 buffer.fPixelType = ttByte;
733 buffer.fPixelSize = sizeof(uint8_t);
scroggoe6459652016-01-30 10:06:11 -0800734 buffer.fRowStep = width * 3;
yujieqin916de9f2016-01-25 08:26:16 -0800735
736 for (int i = 0; i < height; ++i) {
737 buffer.fArea = dng_rect(i, 0, i + 1, width);
738
739 try {
740 image->Get(buffer, dng_image::edge_zero);
741 } catch (...) {
742 *rowsDecoded = i;
nagarajan.nf398dd52017-09-19 17:46:52 +0530743 return kIncompleteInput;
yujieqin916de9f2016-01-25 08:26:16 -0800744 }
745
Matt Saretta225e9b2016-11-07 10:26:17 -0500746 if (this->colorXform()) {
747 swizzler->swizzle(xformBuffer.get(), &srcRow[0]);
748
Leon Scroggins III33d53942018-08-22 16:46:32 -0400749 this->applyColorXform(dstRow, xformBuffer.get(), dstInfo.width(), kOpaque_SkAlphaType);
Matt Saretta225e9b2016-11-07 10:26:17 -0500750 } else {
751 swizzler->swizzle(dstRow, &srcRow[0]);
Matt Saretta225e9b2016-11-07 10:26:17 -0500752 }
nagarajan.nf398dd52017-09-19 17:46:52 +0530753 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
yujieqin916de9f2016-01-25 08:26:16 -0800754 }
755 return kSuccess;
756}
757
758SkISize SkRawCodec::onGetScaledDimensions(float desiredScale) const {
759 SkASSERT(desiredScale <= 1.f);
yujieqind0e08852016-03-03 07:38:27 -0800760
yujieqin916de9f2016-01-25 08:26:16 -0800761 const SkISize dim = this->getInfo().dimensions();
yujieqind0e08852016-03-03 07:38:27 -0800762 SkASSERT(dim.fWidth != 0 && dim.fHeight != 0);
763
yujieqin916de9f2016-01-25 08:26:16 -0800764 if (!fDngImage->isScalable()) {
765 return dim;
766 }
767
768 // Limits the minimum size to be 80 on the short edge.
yujieqin076d83d2016-01-27 08:25:53 -0800769 const float shortEdge = static_cast<float>(SkTMin(dim.fWidth, dim.fHeight));
yujieqin916de9f2016-01-25 08:26:16 -0800770 if (desiredScale < 80.f / shortEdge) {
771 desiredScale = 80.f / shortEdge;
772 }
773
774 // For Xtrans images, the integer-factor scaling does not support the half-size scaling case
775 // (stronger downscalings are fine). In this case, returns the factor "3" scaling instead.
776 if (fDngImage->isXtransImage() && desiredScale > 1.f / 3.f && desiredScale < 1.f) {
777 desiredScale = 1.f / 3.f;
778 }
779
780 // Round to integer-factors.
781 const float finalScale = std::floor(1.f/ desiredScale);
yujieqin076d83d2016-01-27 08:25:53 -0800782 return SkISize::Make(static_cast<int32_t>(std::floor(dim.fWidth / finalScale)),
783 static_cast<int32_t>(std::floor(dim.fHeight / finalScale)));
yujieqin916de9f2016-01-25 08:26:16 -0800784}
785
786bool SkRawCodec::onDimensionsSupported(const SkISize& dim) {
787 const SkISize fullDim = this->getInfo().dimensions();
yujieqin076d83d2016-01-27 08:25:53 -0800788 const float fullShortEdge = static_cast<float>(SkTMin(fullDim.fWidth, fullDim.fHeight));
789 const float shortEdge = static_cast<float>(SkTMin(dim.fWidth, dim.fHeight));
yujieqin916de9f2016-01-25 08:26:16 -0800790
791 SkISize sizeFloor = this->onGetScaledDimensions(1.f / std::floor(fullShortEdge / shortEdge));
792 SkISize sizeCeil = this->onGetScaledDimensions(1.f / std::ceil(fullShortEdge / shortEdge));
793 return sizeFloor == dim || sizeCeil == dim;
794}
795
796SkRawCodec::~SkRawCodec() {}
797
798SkRawCodec::SkRawCodec(SkDngImage* dngImage)
Leon Scroggins III33d53942018-08-22 16:46:32 -0400799 : INHERITED(dngImage->width(), dngImage->height(), dngImage->getEncodedInfo(),
800 SkColorSpaceXform::kRGBA_8888_ColorFormat, nullptr,
801 SkColorSpace::MakeSRGB())
yujieqin916de9f2016-01-25 08:26:16 -0800802 , fDngImage(dngImage) {}