1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2016 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/codec/SkCodec.h"
9cb93a386Sopenharmony_ci#include "include/core/SkData.h"
10cb93a386Sopenharmony_ci#include "include/core/SkRefCnt.h"
11cb93a386Sopenharmony_ci#include "include/core/SkStream.h"
12cb93a386Sopenharmony_ci#include "include/core/SkTypes.h"
13cb93a386Sopenharmony_ci#include "include/private/SkColorData.h"
14cb93a386Sopenharmony_ci#include "include/private/SkMutex.h"
15cb93a386Sopenharmony_ci#include "include/private/SkTArray.h"
16cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h"
17cb93a386Sopenharmony_ci#include "src/codec/SkCodecPriv.h"
18cb93a386Sopenharmony_ci#include "src/codec/SkJpegCodec.h"
19cb93a386Sopenharmony_ci#include "src/codec/SkRawCodec.h"
20cb93a386Sopenharmony_ci#include "src/core/SkColorSpacePriv.h"
21cb93a386Sopenharmony_ci#include "src/core/SkStreamPriv.h"
22cb93a386Sopenharmony_ci#include "src/core/SkTaskGroup.h"
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ci#include "dng_area_task.h"
25cb93a386Sopenharmony_ci#include "dng_color_space.h"
26cb93a386Sopenharmony_ci#include "dng_errors.h"
27cb93a386Sopenharmony_ci#include "dng_exceptions.h"
28cb93a386Sopenharmony_ci#include "dng_host.h"
29cb93a386Sopenharmony_ci#include "dng_info.h"
30cb93a386Sopenharmony_ci#include "dng_memory.h"
31cb93a386Sopenharmony_ci#include "dng_render.h"
32cb93a386Sopenharmony_ci#include "dng_stream.h"
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_ci#include "src/piex.h"
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ci#include <cmath>  // for std::round,floor,ceil
37cb93a386Sopenharmony_ci#include <limits>
38cb93a386Sopenharmony_ci#include <memory>
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_cinamespace {
41cb93a386Sopenharmony_ci
42cb93a386Sopenharmony_ci// Caluclates the number of tiles of tile_size that fit into the area in vertical and horizontal
43cb93a386Sopenharmony_ci// directions.
44cb93a386Sopenharmony_cidng_point num_tiles_in_area(const dng_point &areaSize,
45cb93a386Sopenharmony_ci                            const dng_point_real64 &tileSize) {
46cb93a386Sopenharmony_ci  // FIXME: Add a ceil_div() helper in SkCodecPriv.h
47cb93a386Sopenharmony_ci  return dng_point(static_cast<int32>((areaSize.v + tileSize.v - 1) / tileSize.v),
48cb93a386Sopenharmony_ci                   static_cast<int32>((areaSize.h + tileSize.h - 1) / tileSize.h));
49cb93a386Sopenharmony_ci}
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ciint num_tasks_required(const dng_point& tilesInTask,
52cb93a386Sopenharmony_ci                         const dng_point& tilesInArea) {
53cb93a386Sopenharmony_ci  return ((tilesInArea.v + tilesInTask.v - 1) / tilesInTask.v) *
54cb93a386Sopenharmony_ci         ((tilesInArea.h + tilesInTask.h - 1) / tilesInTask.h);
55cb93a386Sopenharmony_ci}
56cb93a386Sopenharmony_ci
57cb93a386Sopenharmony_ci// Calculate the number of tiles to process per task, taking into account the maximum number of
58cb93a386Sopenharmony_ci// tasks. It prefers to increase horizontally for better locality of reference.
59cb93a386Sopenharmony_cidng_point num_tiles_per_task(const int maxTasks,
60cb93a386Sopenharmony_ci                             const dng_point &tilesInArea) {
61cb93a386Sopenharmony_ci  dng_point tilesInTask = {1, 1};
62cb93a386Sopenharmony_ci  while (num_tasks_required(tilesInTask, tilesInArea) > maxTasks) {
63cb93a386Sopenharmony_ci      if (tilesInTask.h < tilesInArea.h) {
64cb93a386Sopenharmony_ci          ++tilesInTask.h;
65cb93a386Sopenharmony_ci      } else if (tilesInTask.v < tilesInArea.v) {
66cb93a386Sopenharmony_ci          ++tilesInTask.v;
67cb93a386Sopenharmony_ci      } else {
68cb93a386Sopenharmony_ci          ThrowProgramError("num_tiles_per_task calculation is wrong.");
69cb93a386Sopenharmony_ci      }
70cb93a386Sopenharmony_ci  }
71cb93a386Sopenharmony_ci  return tilesInTask;
72cb93a386Sopenharmony_ci}
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_cistd::vector<dng_rect> compute_task_areas(const int maxTasks, const dng_rect& area,
75cb93a386Sopenharmony_ci                                         const dng_point& tileSize) {
76cb93a386Sopenharmony_ci  std::vector<dng_rect> taskAreas;
77cb93a386Sopenharmony_ci  const dng_point tilesInArea = num_tiles_in_area(area.Size(), tileSize);
78cb93a386Sopenharmony_ci  const dng_point tilesPerTask = num_tiles_per_task(maxTasks, tilesInArea);
79cb93a386Sopenharmony_ci  const dng_point taskAreaSize = {tilesPerTask.v * tileSize.v,
80cb93a386Sopenharmony_ci                                    tilesPerTask.h * tileSize.h};
81cb93a386Sopenharmony_ci  for (int v = 0; v < tilesInArea.v; v += tilesPerTask.v) {
82cb93a386Sopenharmony_ci    for (int h = 0; h < tilesInArea.h; h += tilesPerTask.h) {
83cb93a386Sopenharmony_ci      dng_rect taskArea;
84cb93a386Sopenharmony_ci      taskArea.t = area.t + v * tileSize.v;
85cb93a386Sopenharmony_ci      taskArea.l = area.l + h * tileSize.h;
86cb93a386Sopenharmony_ci      taskArea.b = Min_int32(taskArea.t + taskAreaSize.v, area.b);
87cb93a386Sopenharmony_ci      taskArea.r = Min_int32(taskArea.l + taskAreaSize.h, area.r);
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_ci      taskAreas.push_back(taskArea);
90cb93a386Sopenharmony_ci    }
91cb93a386Sopenharmony_ci  }
92cb93a386Sopenharmony_ci  return taskAreas;
93cb93a386Sopenharmony_ci}
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ciclass SkDngHost : public dng_host {
96cb93a386Sopenharmony_cipublic:
97cb93a386Sopenharmony_ci    explicit SkDngHost(dng_memory_allocator* allocater) : dng_host(allocater) {}
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci    void PerformAreaTask(dng_area_task& task, const dng_rect& area) override {
100cb93a386Sopenharmony_ci        SkTaskGroup taskGroup;
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_ci        // tileSize is typically 256x256
103cb93a386Sopenharmony_ci        const dng_point tileSize(task.FindTileSize(area));
104cb93a386Sopenharmony_ci        const std::vector<dng_rect> taskAreas = compute_task_areas(this->PerformAreaTaskThreads(),
105cb93a386Sopenharmony_ci                                                                   area, tileSize);
106cb93a386Sopenharmony_ci        const int numTasks = static_cast<int>(taskAreas.size());
107cb93a386Sopenharmony_ci
108cb93a386Sopenharmony_ci        SkMutex mutex;
109cb93a386Sopenharmony_ci        SkTArray<dng_exception> exceptions;
110cb93a386Sopenharmony_ci        task.Start(numTasks, tileSize, &Allocator(), Sniffer());
111cb93a386Sopenharmony_ci        for (int taskIndex = 0; taskIndex < numTasks; ++taskIndex) {
112cb93a386Sopenharmony_ci            taskGroup.add([&mutex, &exceptions, &task, this, taskIndex, taskAreas, tileSize] {
113cb93a386Sopenharmony_ci                try {
114cb93a386Sopenharmony_ci                    task.ProcessOnThread(taskIndex, taskAreas[taskIndex], tileSize, this->Sniffer());
115cb93a386Sopenharmony_ci                } catch (dng_exception& exception) {
116cb93a386Sopenharmony_ci                    SkAutoMutexExclusive lock(mutex);
117cb93a386Sopenharmony_ci                    exceptions.push_back(exception);
118cb93a386Sopenharmony_ci                } catch (...) {
119cb93a386Sopenharmony_ci                    SkAutoMutexExclusive lock(mutex);
120cb93a386Sopenharmony_ci                    exceptions.push_back(dng_exception(dng_error_unknown));
121cb93a386Sopenharmony_ci                }
122cb93a386Sopenharmony_ci            });
123cb93a386Sopenharmony_ci        }
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ci        taskGroup.wait();
126cb93a386Sopenharmony_ci        task.Finish(numTasks);
127cb93a386Sopenharmony_ci
128cb93a386Sopenharmony_ci        // We only re-throw the first exception.
129cb93a386Sopenharmony_ci        if (!exceptions.empty()) {
130cb93a386Sopenharmony_ci            Throw_dng_error(exceptions.front().ErrorCode(), nullptr, nullptr);
131cb93a386Sopenharmony_ci        }
132cb93a386Sopenharmony_ci    }
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_ci    uint32 PerformAreaTaskThreads() override {
135cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_ANDROID
136cb93a386Sopenharmony_ci        // Only use 1 thread. DNGs with the warp effect require a lot of memory,
137cb93a386Sopenharmony_ci        // and the amount of memory required scales linearly with the number of
138cb93a386Sopenharmony_ci        // threads. The sample used in CTS requires over 500 MB, so even two
139cb93a386Sopenharmony_ci        // threads is significantly expensive. There is no good way to tell
140cb93a386Sopenharmony_ci        // whether the image has the warp effect.
141cb93a386Sopenharmony_ci        return 1;
142cb93a386Sopenharmony_ci#else
143cb93a386Sopenharmony_ci        return kMaxMPThreads;
144cb93a386Sopenharmony_ci#endif
145cb93a386Sopenharmony_ci    }
146cb93a386Sopenharmony_ci
147cb93a386Sopenharmony_ciprivate:
148cb93a386Sopenharmony_ci    using INHERITED = dng_host;
149cb93a386Sopenharmony_ci};
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_ci// T must be unsigned type.
152cb93a386Sopenharmony_citemplate <class T>
153cb93a386Sopenharmony_cibool safe_add_to_size_t(T arg1, T arg2, size_t* result) {
154cb93a386Sopenharmony_ci    SkASSERT(arg1 >= 0);
155cb93a386Sopenharmony_ci    SkASSERT(arg2 >= 0);
156cb93a386Sopenharmony_ci    if (arg1 >= 0 && arg2 <= std::numeric_limits<T>::max() - arg1) {
157cb93a386Sopenharmony_ci        T sum = arg1 + arg2;
158cb93a386Sopenharmony_ci        if (sum <= std::numeric_limits<size_t>::max()) {
159cb93a386Sopenharmony_ci            *result = static_cast<size_t>(sum);
160cb93a386Sopenharmony_ci            return true;
161cb93a386Sopenharmony_ci        }
162cb93a386Sopenharmony_ci    }
163cb93a386Sopenharmony_ci    return false;
164cb93a386Sopenharmony_ci}
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_cibool is_asset_stream(const SkStream& stream) {
167cb93a386Sopenharmony_ci    return stream.hasLength() && stream.hasPosition();
168cb93a386Sopenharmony_ci}
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci}  // namespace
171cb93a386Sopenharmony_ci
172cb93a386Sopenharmony_ciclass SkRawStream {
173cb93a386Sopenharmony_cipublic:
174cb93a386Sopenharmony_ci    virtual ~SkRawStream() {}
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_ci   /*
177cb93a386Sopenharmony_ci    * Gets the length of the stream. Depending on the type of stream, this may require reading to
178cb93a386Sopenharmony_ci    * the end of the stream.
179cb93a386Sopenharmony_ci    */
180cb93a386Sopenharmony_ci   virtual uint64 getLength() = 0;
181cb93a386Sopenharmony_ci
182cb93a386Sopenharmony_ci   virtual bool read(void* data, size_t offset, size_t length) = 0;
183cb93a386Sopenharmony_ci
184cb93a386Sopenharmony_ci    /*
185cb93a386Sopenharmony_ci     * Creates an SkMemoryStream from the offset with size.
186cb93a386Sopenharmony_ci     * Note: for performance reason, this function is destructive to the SkRawStream. One should
187cb93a386Sopenharmony_ci     *       abandon current object after the function call.
188cb93a386Sopenharmony_ci     */
189cb93a386Sopenharmony_ci   virtual std::unique_ptr<SkMemoryStream> transferBuffer(size_t offset, size_t size) = 0;
190cb93a386Sopenharmony_ci};
191cb93a386Sopenharmony_ci
192cb93a386Sopenharmony_ciclass SkRawLimitedDynamicMemoryWStream : public SkDynamicMemoryWStream {
193cb93a386Sopenharmony_cipublic:
194cb93a386Sopenharmony_ci    ~SkRawLimitedDynamicMemoryWStream() override {}
195cb93a386Sopenharmony_ci
196cb93a386Sopenharmony_ci    bool write(const void* buffer, size_t size) override {
197cb93a386Sopenharmony_ci        size_t newSize;
198cb93a386Sopenharmony_ci        if (!safe_add_to_size_t(this->bytesWritten(), size, &newSize) ||
199cb93a386Sopenharmony_ci            newSize > kMaxStreamSize)
200cb93a386Sopenharmony_ci        {
201cb93a386Sopenharmony_ci            SkCodecPrintf("Error: Stream size exceeds the limit.\n");
202cb93a386Sopenharmony_ci            return false;
203cb93a386Sopenharmony_ci        }
204cb93a386Sopenharmony_ci        return this->INHERITED::write(buffer, size);
205cb93a386Sopenharmony_ci    }
206cb93a386Sopenharmony_ci
207cb93a386Sopenharmony_ciprivate:
208cb93a386Sopenharmony_ci    // Most of valid RAW images will not be larger than 100MB. This limit is helpful to avoid
209cb93a386Sopenharmony_ci    // streaming too large data chunk. We can always adjust the limit here if we need.
210cb93a386Sopenharmony_ci    const size_t kMaxStreamSize = 100 * 1024 * 1024;  // 100MB
211cb93a386Sopenharmony_ci
212cb93a386Sopenharmony_ci    using INHERITED = SkDynamicMemoryWStream;
213cb93a386Sopenharmony_ci};
214cb93a386Sopenharmony_ci
215cb93a386Sopenharmony_ci// Note: the maximum buffer size is 100MB (limited by SkRawLimitedDynamicMemoryWStream).
216cb93a386Sopenharmony_ciclass SkRawBufferedStream : public SkRawStream {
217cb93a386Sopenharmony_cipublic:
218cb93a386Sopenharmony_ci    explicit SkRawBufferedStream(std::unique_ptr<SkStream> stream)
219cb93a386Sopenharmony_ci        : fStream(std::move(stream))
220cb93a386Sopenharmony_ci        , fWholeStreamRead(false)
221cb93a386Sopenharmony_ci    {
222cb93a386Sopenharmony_ci        // Only use SkRawBufferedStream when the stream is not an asset stream.
223cb93a386Sopenharmony_ci        SkASSERT(!is_asset_stream(*fStream));
224cb93a386Sopenharmony_ci    }
225cb93a386Sopenharmony_ci
226cb93a386Sopenharmony_ci    ~SkRawBufferedStream() override {}
227cb93a386Sopenharmony_ci
228cb93a386Sopenharmony_ci    uint64 getLength() override {
229cb93a386Sopenharmony_ci        if (!this->bufferMoreData(kReadToEnd)) {  // read whole stream
230cb93a386Sopenharmony_ci            ThrowReadFile();
231cb93a386Sopenharmony_ci        }
232cb93a386Sopenharmony_ci        return fStreamBuffer.bytesWritten();
233cb93a386Sopenharmony_ci    }
234cb93a386Sopenharmony_ci
235cb93a386Sopenharmony_ci    bool read(void* data, size_t offset, size_t length) override {
236cb93a386Sopenharmony_ci        if (length == 0) {
237cb93a386Sopenharmony_ci            return true;
238cb93a386Sopenharmony_ci        }
239cb93a386Sopenharmony_ci
240cb93a386Sopenharmony_ci        size_t sum;
241cb93a386Sopenharmony_ci        if (!safe_add_to_size_t(offset, length, &sum)) {
242cb93a386Sopenharmony_ci            return false;
243cb93a386Sopenharmony_ci        }
244cb93a386Sopenharmony_ci
245cb93a386Sopenharmony_ci        return this->bufferMoreData(sum) && fStreamBuffer.read(data, offset, length);
246cb93a386Sopenharmony_ci    }
247cb93a386Sopenharmony_ci
248cb93a386Sopenharmony_ci    std::unique_ptr<SkMemoryStream> transferBuffer(size_t offset, size_t size) override {
249cb93a386Sopenharmony_ci        sk_sp<SkData> data(SkData::MakeUninitialized(size));
250cb93a386Sopenharmony_ci        if (offset > fStreamBuffer.bytesWritten()) {
251cb93a386Sopenharmony_ci            // If the offset is not buffered, read from fStream directly and skip the buffering.
252cb93a386Sopenharmony_ci            const size_t skipLength = offset - fStreamBuffer.bytesWritten();
253cb93a386Sopenharmony_ci            if (fStream->skip(skipLength) != skipLength) {
254cb93a386Sopenharmony_ci                return nullptr;
255cb93a386Sopenharmony_ci            }
256cb93a386Sopenharmony_ci            const size_t bytesRead = fStream->read(data->writable_data(), size);
257cb93a386Sopenharmony_ci            if (bytesRead < size) {
258cb93a386Sopenharmony_ci                data = SkData::MakeSubset(data.get(), 0, bytesRead);
259cb93a386Sopenharmony_ci            }
260cb93a386Sopenharmony_ci        } else {
261cb93a386Sopenharmony_ci            const size_t alreadyBuffered = std::min(fStreamBuffer.bytesWritten() - offset, size);
262cb93a386Sopenharmony_ci            if (alreadyBuffered > 0 &&
263cb93a386Sopenharmony_ci                !fStreamBuffer.read(data->writable_data(), offset, alreadyBuffered)) {
264cb93a386Sopenharmony_ci                return nullptr;
265cb93a386Sopenharmony_ci            }
266cb93a386Sopenharmony_ci
267cb93a386Sopenharmony_ci            const size_t remaining = size - alreadyBuffered;
268cb93a386Sopenharmony_ci            if (remaining) {
269cb93a386Sopenharmony_ci                auto* dst = static_cast<uint8_t*>(data->writable_data()) + alreadyBuffered;
270cb93a386Sopenharmony_ci                const size_t bytesRead = fStream->read(dst, remaining);
271cb93a386Sopenharmony_ci                size_t newSize;
272cb93a386Sopenharmony_ci                if (bytesRead < remaining) {
273cb93a386Sopenharmony_ci                    if (!safe_add_to_size_t(alreadyBuffered, bytesRead, &newSize)) {
274cb93a386Sopenharmony_ci                        return nullptr;
275cb93a386Sopenharmony_ci                    }
276cb93a386Sopenharmony_ci                    data = SkData::MakeSubset(data.get(), 0, newSize);
277cb93a386Sopenharmony_ci                }
278cb93a386Sopenharmony_ci            }
279cb93a386Sopenharmony_ci        }
280cb93a386Sopenharmony_ci        return SkMemoryStream::Make(data);
281cb93a386Sopenharmony_ci    }
282cb93a386Sopenharmony_ci
283cb93a386Sopenharmony_ciprivate:
284cb93a386Sopenharmony_ci    // Note: if the newSize == kReadToEnd (0), this function will read to the end of stream.
285cb93a386Sopenharmony_ci    bool bufferMoreData(size_t newSize) {
286cb93a386Sopenharmony_ci        if (newSize == kReadToEnd) {
287cb93a386Sopenharmony_ci            if (fWholeStreamRead) {  // already read-to-end.
288cb93a386Sopenharmony_ci                return true;
289cb93a386Sopenharmony_ci            }
290cb93a386Sopenharmony_ci
291cb93a386Sopenharmony_ci            // TODO: optimize for the special case when the input is SkMemoryStream.
292cb93a386Sopenharmony_ci            return SkStreamCopy(&fStreamBuffer, fStream.get());
293cb93a386Sopenharmony_ci        }
294cb93a386Sopenharmony_ci
295cb93a386Sopenharmony_ci        if (newSize <= fStreamBuffer.bytesWritten()) {  // already buffered to newSize
296cb93a386Sopenharmony_ci            return true;
297cb93a386Sopenharmony_ci        }
298cb93a386Sopenharmony_ci        if (fWholeStreamRead) {  // newSize is larger than the whole stream.
299cb93a386Sopenharmony_ci            return false;
300cb93a386Sopenharmony_ci        }
301cb93a386Sopenharmony_ci
302cb93a386Sopenharmony_ci        // Try to read at least 8192 bytes to avoid to many small reads.
303cb93a386Sopenharmony_ci        const size_t kMinSizeToRead = 8192;
304cb93a386Sopenharmony_ci        const size_t sizeRequested = newSize - fStreamBuffer.bytesWritten();
305cb93a386Sopenharmony_ci        const size_t sizeToRead = std::max(kMinSizeToRead, sizeRequested);
306cb93a386Sopenharmony_ci        SkAutoSTMalloc<kMinSizeToRead, uint8> tempBuffer(sizeToRead);
307cb93a386Sopenharmony_ci        const size_t bytesRead = fStream->read(tempBuffer.get(), sizeToRead);
308cb93a386Sopenharmony_ci        if (bytesRead < sizeRequested) {
309cb93a386Sopenharmony_ci            return false;
310cb93a386Sopenharmony_ci        }
311cb93a386Sopenharmony_ci        return fStreamBuffer.write(tempBuffer.get(), bytesRead);
312cb93a386Sopenharmony_ci    }
313cb93a386Sopenharmony_ci
314cb93a386Sopenharmony_ci    std::unique_ptr<SkStream> fStream;
315cb93a386Sopenharmony_ci    bool fWholeStreamRead;
316cb93a386Sopenharmony_ci
317cb93a386Sopenharmony_ci    // Use a size-limited stream to avoid holding too huge buffer.
318cb93a386Sopenharmony_ci    SkRawLimitedDynamicMemoryWStream fStreamBuffer;
319cb93a386Sopenharmony_ci
320cb93a386Sopenharmony_ci    const size_t kReadToEnd = 0;
321cb93a386Sopenharmony_ci};
322cb93a386Sopenharmony_ci
323cb93a386Sopenharmony_ciclass SkRawAssetStream : public SkRawStream {
324cb93a386Sopenharmony_cipublic:
325cb93a386Sopenharmony_ci    explicit SkRawAssetStream(std::unique_ptr<SkStream> stream)
326cb93a386Sopenharmony_ci        : fStream(std::move(stream))
327cb93a386Sopenharmony_ci    {
328cb93a386Sopenharmony_ci        // Only use SkRawAssetStream when the stream is an asset stream.
329cb93a386Sopenharmony_ci        SkASSERT(is_asset_stream(*fStream));
330cb93a386Sopenharmony_ci    }
331cb93a386Sopenharmony_ci
332cb93a386Sopenharmony_ci    ~SkRawAssetStream() override {}
333cb93a386Sopenharmony_ci
334cb93a386Sopenharmony_ci    uint64 getLength() override {
335cb93a386Sopenharmony_ci        return fStream->getLength();
336cb93a386Sopenharmony_ci    }
337cb93a386Sopenharmony_ci
338cb93a386Sopenharmony_ci
339cb93a386Sopenharmony_ci    bool read(void* data, size_t offset, size_t length) override {
340cb93a386Sopenharmony_ci        if (length == 0) {
341cb93a386Sopenharmony_ci            return true;
342cb93a386Sopenharmony_ci        }
343cb93a386Sopenharmony_ci
344cb93a386Sopenharmony_ci        size_t sum;
345cb93a386Sopenharmony_ci        if (!safe_add_to_size_t(offset, length, &sum)) {
346cb93a386Sopenharmony_ci            return false;
347cb93a386Sopenharmony_ci        }
348cb93a386Sopenharmony_ci
349cb93a386Sopenharmony_ci        return fStream->seek(offset) && (fStream->read(data, length) == length);
350cb93a386Sopenharmony_ci    }
351cb93a386Sopenharmony_ci
352cb93a386Sopenharmony_ci    std::unique_ptr<SkMemoryStream> transferBuffer(size_t offset, size_t size) override {
353cb93a386Sopenharmony_ci        if (fStream->getLength() < offset) {
354cb93a386Sopenharmony_ci            return nullptr;
355cb93a386Sopenharmony_ci        }
356cb93a386Sopenharmony_ci
357cb93a386Sopenharmony_ci        size_t sum;
358cb93a386Sopenharmony_ci        if (!safe_add_to_size_t(offset, size, &sum)) {
359cb93a386Sopenharmony_ci            return nullptr;
360cb93a386Sopenharmony_ci        }
361cb93a386Sopenharmony_ci
362cb93a386Sopenharmony_ci        // This will allow read less than the requested "size", because the JPEG codec wants to
363cb93a386Sopenharmony_ci        // handle also a partial JPEG file.
364cb93a386Sopenharmony_ci        const size_t bytesToRead = std::min(sum, fStream->getLength()) - offset;
365cb93a386Sopenharmony_ci        if (bytesToRead == 0) {
366cb93a386Sopenharmony_ci            return nullptr;
367cb93a386Sopenharmony_ci        }
368cb93a386Sopenharmony_ci
369cb93a386Sopenharmony_ci        if (fStream->getMemoryBase()) {  // directly copy if getMemoryBase() is available.
370cb93a386Sopenharmony_ci            sk_sp<SkData> data(SkData::MakeWithCopy(
371cb93a386Sopenharmony_ci                static_cast<const uint8_t*>(fStream->getMemoryBase()) + offset, bytesToRead));
372cb93a386Sopenharmony_ci            fStream.reset();
373cb93a386Sopenharmony_ci            return SkMemoryStream::Make(data);
374cb93a386Sopenharmony_ci        } else {
375cb93a386Sopenharmony_ci            sk_sp<SkData> data(SkData::MakeUninitialized(bytesToRead));
376cb93a386Sopenharmony_ci            if (!fStream->seek(offset)) {
377cb93a386Sopenharmony_ci                return nullptr;
378cb93a386Sopenharmony_ci            }
379cb93a386Sopenharmony_ci            const size_t bytesRead = fStream->read(data->writable_data(), bytesToRead);
380cb93a386Sopenharmony_ci            if (bytesRead < bytesToRead) {
381cb93a386Sopenharmony_ci                data = SkData::MakeSubset(data.get(), 0, bytesRead);
382cb93a386Sopenharmony_ci            }
383cb93a386Sopenharmony_ci            return SkMemoryStream::Make(data);
384cb93a386Sopenharmony_ci        }
385cb93a386Sopenharmony_ci    }
386cb93a386Sopenharmony_ciprivate:
387cb93a386Sopenharmony_ci    std::unique_ptr<SkStream> fStream;
388cb93a386Sopenharmony_ci};
389cb93a386Sopenharmony_ci
390cb93a386Sopenharmony_ciclass SkPiexStream : public ::piex::StreamInterface {
391cb93a386Sopenharmony_cipublic:
392cb93a386Sopenharmony_ci    // Will NOT take the ownership of the stream.
393cb93a386Sopenharmony_ci    explicit SkPiexStream(SkRawStream* stream) : fStream(stream) {}
394cb93a386Sopenharmony_ci
395cb93a386Sopenharmony_ci    ~SkPiexStream() override {}
396cb93a386Sopenharmony_ci
397cb93a386Sopenharmony_ci    ::piex::Error GetData(const size_t offset, const size_t length,
398cb93a386Sopenharmony_ci                          uint8* data) override {
399cb93a386Sopenharmony_ci        return fStream->read(static_cast<void*>(data), offset, length) ?
400cb93a386Sopenharmony_ci            ::piex::Error::kOk : ::piex::Error::kFail;
401cb93a386Sopenharmony_ci    }
402cb93a386Sopenharmony_ci
403cb93a386Sopenharmony_ciprivate:
404cb93a386Sopenharmony_ci    SkRawStream* fStream;
405cb93a386Sopenharmony_ci};
406cb93a386Sopenharmony_ci
407cb93a386Sopenharmony_ciclass SkDngStream : public dng_stream {
408cb93a386Sopenharmony_cipublic:
409cb93a386Sopenharmony_ci    // Will NOT take the ownership of the stream.
410cb93a386Sopenharmony_ci    SkDngStream(SkRawStream* stream) : fStream(stream) {}
411cb93a386Sopenharmony_ci
412cb93a386Sopenharmony_ci    ~SkDngStream() override {}
413cb93a386Sopenharmony_ci
414cb93a386Sopenharmony_ci    uint64 DoGetLength() override { return fStream->getLength(); }
415cb93a386Sopenharmony_ci
416cb93a386Sopenharmony_ci    void DoRead(void* data, uint32 count, uint64 offset) override {
417cb93a386Sopenharmony_ci        size_t sum;
418cb93a386Sopenharmony_ci        if (!safe_add_to_size_t(static_cast<uint64>(count), offset, &sum) ||
419cb93a386Sopenharmony_ci            !fStream->read(data, static_cast<size_t>(offset), static_cast<size_t>(count))) {
420cb93a386Sopenharmony_ci            ThrowReadFile();
421cb93a386Sopenharmony_ci        }
422cb93a386Sopenharmony_ci    }
423cb93a386Sopenharmony_ci
424cb93a386Sopenharmony_ciprivate:
425cb93a386Sopenharmony_ci    SkRawStream* fStream;
426cb93a386Sopenharmony_ci};
427cb93a386Sopenharmony_ci
428cb93a386Sopenharmony_ciclass SkDngImage {
429cb93a386Sopenharmony_cipublic:
430cb93a386Sopenharmony_ci    /*
431cb93a386Sopenharmony_ci     * Initializes the object with the information from Piex in a first attempt. This way it can
432cb93a386Sopenharmony_ci     * save time and storage to obtain the DNG dimensions and color filter array (CFA) pattern
433cb93a386Sopenharmony_ci     * which is essential for the demosaicing of the sensor image.
434cb93a386Sopenharmony_ci     * Note: this will take the ownership of the stream.
435cb93a386Sopenharmony_ci     */
436cb93a386Sopenharmony_ci    static SkDngImage* NewFromStream(SkRawStream* stream) {
437cb93a386Sopenharmony_ci        std::unique_ptr<SkDngImage> dngImage(new SkDngImage(stream));
438cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_LIBFUZZER)
439cb93a386Sopenharmony_ci        // Libfuzzer easily runs out of memory after here. To avoid that
440cb93a386Sopenharmony_ci        // We just pretend all streams are invalid. Our AFL-fuzzer
441cb93a386Sopenharmony_ci        // should still exercise this code; it's more resistant to OOM.
442cb93a386Sopenharmony_ci        return nullptr;
443cb93a386Sopenharmony_ci#endif
444cb93a386Sopenharmony_ci        if (!dngImage->initFromPiex() && !dngImage->readDng()) {
445cb93a386Sopenharmony_ci            return nullptr;
446cb93a386Sopenharmony_ci        }
447cb93a386Sopenharmony_ci
448cb93a386Sopenharmony_ci        return dngImage.release();
449cb93a386Sopenharmony_ci    }
450cb93a386Sopenharmony_ci
451cb93a386Sopenharmony_ci    /*
452cb93a386Sopenharmony_ci     * Renders the DNG image to the size. The DNG SDK only allows scaling close to integer factors
453cb93a386Sopenharmony_ci     * down to 80 pixels on the short edge. The rendered image will be close to the specified size,
454cb93a386Sopenharmony_ci     * but there is no guarantee that any of the edges will match the requested size. E.g.
455cb93a386Sopenharmony_ci     *   100% size:              4000 x 3000
456cb93a386Sopenharmony_ci     *   requested size:         1600 x 1200
457cb93a386Sopenharmony_ci     *   returned size could be: 2000 x 1500
458cb93a386Sopenharmony_ci     */
459cb93a386Sopenharmony_ci    dng_image* render(int width, int height) {
460cb93a386Sopenharmony_ci        if (!fHost || !fInfo || !fNegative || !fDngStream) {
461cb93a386Sopenharmony_ci            if (!this->readDng()) {
462cb93a386Sopenharmony_ci                return nullptr;
463cb93a386Sopenharmony_ci            }
464cb93a386Sopenharmony_ci        }
465cb93a386Sopenharmony_ci
466cb93a386Sopenharmony_ci        // DNG SDK preserves the aspect ratio, so it only needs to know the longer dimension.
467cb93a386Sopenharmony_ci        const int preferredSize = std::max(width, height);
468cb93a386Sopenharmony_ci        try {
469cb93a386Sopenharmony_ci            // render() takes ownership of fHost, fInfo, fNegative and fDngStream when available.
470cb93a386Sopenharmony_ci            std::unique_ptr<dng_host> host(fHost.release());
471cb93a386Sopenharmony_ci            std::unique_ptr<dng_info> info(fInfo.release());
472cb93a386Sopenharmony_ci            std::unique_ptr<dng_negative> negative(fNegative.release());
473cb93a386Sopenharmony_ci            std::unique_ptr<dng_stream> dngStream(fDngStream.release());
474cb93a386Sopenharmony_ci
475cb93a386Sopenharmony_ci            host->SetPreferredSize(preferredSize);
476cb93a386Sopenharmony_ci            host->ValidateSizes();
477cb93a386Sopenharmony_ci
478cb93a386Sopenharmony_ci            negative->ReadStage1Image(*host, *dngStream, *info);
479cb93a386Sopenharmony_ci
480cb93a386Sopenharmony_ci            if (info->fMaskIndex != -1) {
481cb93a386Sopenharmony_ci                negative->ReadTransparencyMask(*host, *dngStream, *info);
482cb93a386Sopenharmony_ci            }
483cb93a386Sopenharmony_ci
484cb93a386Sopenharmony_ci            negative->ValidateRawImageDigest(*host);
485cb93a386Sopenharmony_ci            if (negative->IsDamaged()) {
486cb93a386Sopenharmony_ci                return nullptr;
487cb93a386Sopenharmony_ci            }
488cb93a386Sopenharmony_ci
489cb93a386Sopenharmony_ci            const int32 kMosaicPlane = -1;
490cb93a386Sopenharmony_ci            negative->BuildStage2Image(*host);
491cb93a386Sopenharmony_ci            negative->BuildStage3Image(*host, kMosaicPlane);
492cb93a386Sopenharmony_ci
493cb93a386Sopenharmony_ci            dng_render render(*host, *negative);
494cb93a386Sopenharmony_ci            render.SetFinalSpace(dng_space_sRGB::Get());
495cb93a386Sopenharmony_ci            render.SetFinalPixelType(ttByte);
496cb93a386Sopenharmony_ci
497cb93a386Sopenharmony_ci            dng_point stage3_size = negative->Stage3Image()->Size();
498cb93a386Sopenharmony_ci            render.SetMaximumSize(std::max(stage3_size.h, stage3_size.v));
499cb93a386Sopenharmony_ci
500cb93a386Sopenharmony_ci            return render.Render();
501cb93a386Sopenharmony_ci        } catch (...) {
502cb93a386Sopenharmony_ci            return nullptr;
503cb93a386Sopenharmony_ci        }
504cb93a386Sopenharmony_ci    }
505cb93a386Sopenharmony_ci
506cb93a386Sopenharmony_ci    int width() const {
507cb93a386Sopenharmony_ci        return fWidth;
508cb93a386Sopenharmony_ci    }
509cb93a386Sopenharmony_ci
510cb93a386Sopenharmony_ci    int height() const {
511cb93a386Sopenharmony_ci        return fHeight;
512cb93a386Sopenharmony_ci    }
513cb93a386Sopenharmony_ci
514cb93a386Sopenharmony_ci    bool isScalable() const {
515cb93a386Sopenharmony_ci        return fIsScalable;
516cb93a386Sopenharmony_ci    }
517cb93a386Sopenharmony_ci
518cb93a386Sopenharmony_ci    bool isXtransImage() const {
519cb93a386Sopenharmony_ci        return fIsXtransImage;
520cb93a386Sopenharmony_ci    }
521cb93a386Sopenharmony_ci
522cb93a386Sopenharmony_ci    // Quick check if the image contains a valid TIFF header as requested by DNG format.
523cb93a386Sopenharmony_ci    // Does not affect ownership of stream.
524cb93a386Sopenharmony_ci    static bool IsTiffHeaderValid(SkRawStream* stream) {
525cb93a386Sopenharmony_ci        const size_t kHeaderSize = 4;
526cb93a386Sopenharmony_ci        unsigned char header[kHeaderSize];
527cb93a386Sopenharmony_ci        if (!stream->read(header, 0 /* offset */, kHeaderSize)) {
528cb93a386Sopenharmony_ci            return false;
529cb93a386Sopenharmony_ci        }
530cb93a386Sopenharmony_ci
531cb93a386Sopenharmony_ci        // Check if the header is valid (endian info and magic number "42").
532cb93a386Sopenharmony_ci        bool littleEndian;
533cb93a386Sopenharmony_ci        if (!is_valid_endian_marker(header, &littleEndian)) {
534cb93a386Sopenharmony_ci            return false;
535cb93a386Sopenharmony_ci        }
536cb93a386Sopenharmony_ci
537cb93a386Sopenharmony_ci        return 0x2A == get_endian_short(header + 2, littleEndian);
538cb93a386Sopenharmony_ci    }
539cb93a386Sopenharmony_ci
540cb93a386Sopenharmony_ciprivate:
541cb93a386Sopenharmony_ci    bool init(int width, int height, const dng_point& cfaPatternSize) {
542cb93a386Sopenharmony_ci        fWidth = width;
543cb93a386Sopenharmony_ci        fHeight = height;
544cb93a386Sopenharmony_ci
545cb93a386Sopenharmony_ci        // The DNG SDK scales only during demosaicing, so scaling is only possible when
546cb93a386Sopenharmony_ci        // a mosaic info is available.
547cb93a386Sopenharmony_ci        fIsScalable = cfaPatternSize.v != 0 && cfaPatternSize.h != 0;
548cb93a386Sopenharmony_ci        fIsXtransImage = fIsScalable ? (cfaPatternSize.v == 6 && cfaPatternSize.h == 6) : false;
549cb93a386Sopenharmony_ci
550cb93a386Sopenharmony_ci        return width > 0 && height > 0;
551cb93a386Sopenharmony_ci    }
552cb93a386Sopenharmony_ci
553cb93a386Sopenharmony_ci    bool initFromPiex() {
554cb93a386Sopenharmony_ci        // Does not take the ownership of rawStream.
555cb93a386Sopenharmony_ci        SkPiexStream piexStream(fStream.get());
556cb93a386Sopenharmony_ci        ::piex::PreviewImageData imageData;
557cb93a386Sopenharmony_ci        if (::piex::IsRaw(&piexStream)
558cb93a386Sopenharmony_ci            && ::piex::GetPreviewImageData(&piexStream, &imageData) == ::piex::Error::kOk)
559cb93a386Sopenharmony_ci        {
560cb93a386Sopenharmony_ci            dng_point cfaPatternSize(imageData.cfa_pattern_dim[1], imageData.cfa_pattern_dim[0]);
561cb93a386Sopenharmony_ci            return this->init(static_cast<int>(imageData.full_width),
562cb93a386Sopenharmony_ci                              static_cast<int>(imageData.full_height), cfaPatternSize);
563cb93a386Sopenharmony_ci        }
564cb93a386Sopenharmony_ci        return false;
565cb93a386Sopenharmony_ci    }
566cb93a386Sopenharmony_ci
567cb93a386Sopenharmony_ci    bool readDng() {
568cb93a386Sopenharmony_ci        try {
569cb93a386Sopenharmony_ci            // Due to the limit of DNG SDK, we need to reset host and info.
570cb93a386Sopenharmony_ci            fHost = std::make_unique<SkDngHost>(&fAllocator);
571cb93a386Sopenharmony_ci            fInfo = std::make_unique<dng_info>();
572cb93a386Sopenharmony_ci            fDngStream = std::make_unique<SkDngStream>(fStream.get());
573cb93a386Sopenharmony_ci
574cb93a386Sopenharmony_ci            fHost->ValidateSizes();
575cb93a386Sopenharmony_ci            fInfo->Parse(*fHost, *fDngStream);
576cb93a386Sopenharmony_ci            fInfo->PostParse(*fHost);
577cb93a386Sopenharmony_ci            if (!fInfo->IsValidDNG()) {
578cb93a386Sopenharmony_ci                return false;
579cb93a386Sopenharmony_ci            }
580cb93a386Sopenharmony_ci
581cb93a386Sopenharmony_ci            fNegative.reset(fHost->Make_dng_negative());
582cb93a386Sopenharmony_ci            fNegative->Parse(*fHost, *fDngStream, *fInfo);
583cb93a386Sopenharmony_ci            fNegative->PostParse(*fHost, *fDngStream, *fInfo);
584cb93a386Sopenharmony_ci            fNegative->SynchronizeMetadata();
585cb93a386Sopenharmony_ci
586cb93a386Sopenharmony_ci            dng_point cfaPatternSize(0, 0);
587cb93a386Sopenharmony_ci            if (fNegative->GetMosaicInfo() != nullptr) {
588cb93a386Sopenharmony_ci                cfaPatternSize = fNegative->GetMosaicInfo()->fCFAPatternSize;
589cb93a386Sopenharmony_ci            }
590cb93a386Sopenharmony_ci            return this->init(static_cast<int>(fNegative->DefaultCropSizeH().As_real64()),
591cb93a386Sopenharmony_ci                              static_cast<int>(fNegative->DefaultCropSizeV().As_real64()),
592cb93a386Sopenharmony_ci                              cfaPatternSize);
593cb93a386Sopenharmony_ci        } catch (...) {
594cb93a386Sopenharmony_ci            return false;
595cb93a386Sopenharmony_ci        }
596cb93a386Sopenharmony_ci    }
597cb93a386Sopenharmony_ci
598cb93a386Sopenharmony_ci    SkDngImage(SkRawStream* stream)
599cb93a386Sopenharmony_ci        : fStream(stream)
600cb93a386Sopenharmony_ci    {}
601cb93a386Sopenharmony_ci
602cb93a386Sopenharmony_ci    dng_memory_allocator fAllocator;
603cb93a386Sopenharmony_ci    std::unique_ptr<SkRawStream> fStream;
604cb93a386Sopenharmony_ci    std::unique_ptr<dng_host> fHost;
605cb93a386Sopenharmony_ci    std::unique_ptr<dng_info> fInfo;
606cb93a386Sopenharmony_ci    std::unique_ptr<dng_negative> fNegative;
607cb93a386Sopenharmony_ci    std::unique_ptr<dng_stream> fDngStream;
608cb93a386Sopenharmony_ci
609cb93a386Sopenharmony_ci    int fWidth;
610cb93a386Sopenharmony_ci    int fHeight;
611cb93a386Sopenharmony_ci    bool fIsScalable;
612cb93a386Sopenharmony_ci    bool fIsXtransImage;
613cb93a386Sopenharmony_ci};
614cb93a386Sopenharmony_ci
615cb93a386Sopenharmony_ci/*
616cb93a386Sopenharmony_ci * Tries to handle the image with PIEX. If PIEX returns kOk and finds the preview image, create a
617cb93a386Sopenharmony_ci * SkJpegCodec. If PIEX returns kFail, then the file is invalid, return nullptr. In other cases,
618cb93a386Sopenharmony_ci * fallback to create SkRawCodec for DNG images.
619cb93a386Sopenharmony_ci */
620cb93a386Sopenharmony_cistd::unique_ptr<SkCodec> SkRawCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
621cb93a386Sopenharmony_ci                                                    Result* result) {
622cb93a386Sopenharmony_ci    std::unique_ptr<SkRawStream> rawStream;
623cb93a386Sopenharmony_ci    if (is_asset_stream(*stream)) {
624cb93a386Sopenharmony_ci        rawStream = std::make_unique<SkRawAssetStream>(std::move(stream));
625cb93a386Sopenharmony_ci    } else {
626cb93a386Sopenharmony_ci        rawStream = std::make_unique<SkRawBufferedStream>(std::move(stream));
627cb93a386Sopenharmony_ci    }
628cb93a386Sopenharmony_ci
629cb93a386Sopenharmony_ci    // Does not take the ownership of rawStream.
630cb93a386Sopenharmony_ci    SkPiexStream piexStream(rawStream.get());
631cb93a386Sopenharmony_ci    ::piex::PreviewImageData imageData;
632cb93a386Sopenharmony_ci    if (::piex::IsRaw(&piexStream)) {
633cb93a386Sopenharmony_ci        ::piex::Error error = ::piex::GetPreviewImageData(&piexStream, &imageData);
634cb93a386Sopenharmony_ci        if (error == ::piex::Error::kFail) {
635cb93a386Sopenharmony_ci            *result = kInvalidInput;
636cb93a386Sopenharmony_ci            return nullptr;
637cb93a386Sopenharmony_ci        }
638cb93a386Sopenharmony_ci
639cb93a386Sopenharmony_ci        std::unique_ptr<SkEncodedInfo::ICCProfile> profile;
640cb93a386Sopenharmony_ci        if (imageData.color_space == ::piex::PreviewImageData::kAdobeRgb) {
641cb93a386Sopenharmony_ci            skcms_ICCProfile skcmsProfile;
642cb93a386Sopenharmony_ci            skcms_Init(&skcmsProfile);
643cb93a386Sopenharmony_ci            skcms_SetTransferFunction(&skcmsProfile, &SkNamedTransferFn::k2Dot2);
644cb93a386Sopenharmony_ci            skcms_SetXYZD50(&skcmsProfile, &SkNamedGamut::kAdobeRGB);
645cb93a386Sopenharmony_ci            profile = SkEncodedInfo::ICCProfile::Make(skcmsProfile);
646cb93a386Sopenharmony_ci        }
647cb93a386Sopenharmony_ci
648cb93a386Sopenharmony_ci        //  Theoretically PIEX can return JPEG compressed image or uncompressed RGB image. We only
649cb93a386Sopenharmony_ci        //  handle the JPEG compressed preview image here.
650cb93a386Sopenharmony_ci        if (error == ::piex::Error::kOk && imageData.preview.length > 0 &&
651cb93a386Sopenharmony_ci            imageData.preview.format == ::piex::Image::kJpegCompressed)
652cb93a386Sopenharmony_ci        {
653cb93a386Sopenharmony_ci            // transferBuffer() is destructive to the rawStream. Abandon the rawStream after this
654cb93a386Sopenharmony_ci            // function call.
655cb93a386Sopenharmony_ci            // FIXME: one may avoid the copy of memoryStream and use the buffered rawStream.
656cb93a386Sopenharmony_ci            auto memoryStream = rawStream->transferBuffer(imageData.preview.offset,
657cb93a386Sopenharmony_ci                                                          imageData.preview.length);
658cb93a386Sopenharmony_ci            if (!memoryStream) {
659cb93a386Sopenharmony_ci                *result = kInvalidInput;
660cb93a386Sopenharmony_ci                return nullptr;
661cb93a386Sopenharmony_ci            }
662cb93a386Sopenharmony_ci            return SkJpegCodec::MakeFromStream(std::move(memoryStream), result,
663cb93a386Sopenharmony_ci                                               std::move(profile));
664cb93a386Sopenharmony_ci        }
665cb93a386Sopenharmony_ci    }
666cb93a386Sopenharmony_ci
667cb93a386Sopenharmony_ci    if (!SkDngImage::IsTiffHeaderValid(rawStream.get())) {
668cb93a386Sopenharmony_ci        *result = kUnimplemented;
669cb93a386Sopenharmony_ci        return nullptr;
670cb93a386Sopenharmony_ci    }
671cb93a386Sopenharmony_ci
672cb93a386Sopenharmony_ci    // Takes the ownership of the rawStream.
673cb93a386Sopenharmony_ci    std::unique_ptr<SkDngImage> dngImage(SkDngImage::NewFromStream(rawStream.release()));
674cb93a386Sopenharmony_ci    if (!dngImage) {
675cb93a386Sopenharmony_ci        *result = kInvalidInput;
676cb93a386Sopenharmony_ci        return nullptr;
677cb93a386Sopenharmony_ci    }
678cb93a386Sopenharmony_ci
679cb93a386Sopenharmony_ci    *result = kSuccess;
680cb93a386Sopenharmony_ci    return std::unique_ptr<SkCodec>(new SkRawCodec(dngImage.release()));
681cb93a386Sopenharmony_ci}
682cb93a386Sopenharmony_ci
683cb93a386Sopenharmony_ciSkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
684cb93a386Sopenharmony_ci                                        size_t dstRowBytes, const Options& options,
685cb93a386Sopenharmony_ci                                        int* rowsDecoded) {
686cb93a386Sopenharmony_ci    const int width = dstInfo.width();
687cb93a386Sopenharmony_ci    const int height = dstInfo.height();
688cb93a386Sopenharmony_ci    std::unique_ptr<dng_image> image(fDngImage->render(width, height));
689cb93a386Sopenharmony_ci    if (!image) {
690cb93a386Sopenharmony_ci        return kInvalidInput;
691cb93a386Sopenharmony_ci    }
692cb93a386Sopenharmony_ci
693cb93a386Sopenharmony_ci    // Because the DNG SDK can not guarantee to render to requested size, we allow a small
694cb93a386Sopenharmony_ci    // difference. Only the overlapping region will be converted.
695cb93a386Sopenharmony_ci    const float maxDiffRatio = 1.03f;
696cb93a386Sopenharmony_ci    const dng_point& imageSize = image->Size();
697cb93a386Sopenharmony_ci    if (imageSize.h / (float) width > maxDiffRatio || imageSize.h < width ||
698cb93a386Sopenharmony_ci        imageSize.v / (float) height > maxDiffRatio || imageSize.v < height) {
699cb93a386Sopenharmony_ci        return SkCodec::kInvalidScale;
700cb93a386Sopenharmony_ci    }
701cb93a386Sopenharmony_ci
702cb93a386Sopenharmony_ci    void* dstRow = dst;
703cb93a386Sopenharmony_ci    SkAutoTMalloc<uint8_t> srcRow(width * 3);
704cb93a386Sopenharmony_ci
705cb93a386Sopenharmony_ci    dng_pixel_buffer buffer;
706cb93a386Sopenharmony_ci    buffer.fData = &srcRow[0];
707cb93a386Sopenharmony_ci    buffer.fPlane = 0;
708cb93a386Sopenharmony_ci    buffer.fPlanes = 3;
709cb93a386Sopenharmony_ci    buffer.fColStep = buffer.fPlanes;
710cb93a386Sopenharmony_ci    buffer.fPlaneStep = 1;
711cb93a386Sopenharmony_ci    buffer.fPixelType = ttByte;
712cb93a386Sopenharmony_ci    buffer.fPixelSize = sizeof(uint8_t);
713cb93a386Sopenharmony_ci    buffer.fRowStep = width * 3;
714cb93a386Sopenharmony_ci
715cb93a386Sopenharmony_ci    constexpr auto srcFormat = skcms_PixelFormat_RGB_888;
716cb93a386Sopenharmony_ci    skcms_PixelFormat dstFormat;
717cb93a386Sopenharmony_ci    if (!sk_select_xform_format(dstInfo.colorType(), false, &dstFormat)) {
718cb93a386Sopenharmony_ci        return kInvalidConversion;
719cb93a386Sopenharmony_ci    }
720cb93a386Sopenharmony_ci
721cb93a386Sopenharmony_ci    const skcms_ICCProfile* const srcProfile = this->getEncodedInfo().profile();
722cb93a386Sopenharmony_ci    skcms_ICCProfile dstProfileStorage;
723cb93a386Sopenharmony_ci    const skcms_ICCProfile* dstProfile = nullptr;
724cb93a386Sopenharmony_ci    if (auto cs = dstInfo.colorSpace()) {
725cb93a386Sopenharmony_ci        cs->toProfile(&dstProfileStorage);
726cb93a386Sopenharmony_ci        dstProfile = &dstProfileStorage;
727cb93a386Sopenharmony_ci    }
728cb93a386Sopenharmony_ci
729cb93a386Sopenharmony_ci    for (int i = 0; i < height; ++i) {
730cb93a386Sopenharmony_ci        buffer.fArea = dng_rect(i, 0, i + 1, width);
731cb93a386Sopenharmony_ci
732cb93a386Sopenharmony_ci        try {
733cb93a386Sopenharmony_ci            image->Get(buffer, dng_image::edge_zero);
734cb93a386Sopenharmony_ci        } catch (...) {
735cb93a386Sopenharmony_ci            *rowsDecoded = i;
736cb93a386Sopenharmony_ci            return kIncompleteInput;
737cb93a386Sopenharmony_ci        }
738cb93a386Sopenharmony_ci
739cb93a386Sopenharmony_ci        if (!skcms_Transform(&srcRow[0], srcFormat, skcms_AlphaFormat_Unpremul, srcProfile,
740cb93a386Sopenharmony_ci                             dstRow,     dstFormat, skcms_AlphaFormat_Unpremul, dstProfile,
741cb93a386Sopenharmony_ci                             dstInfo.width())) {
742cb93a386Sopenharmony_ci            SkDebugf("failed to transform\n");
743cb93a386Sopenharmony_ci            *rowsDecoded = i;
744cb93a386Sopenharmony_ci            return kInternalError;
745cb93a386Sopenharmony_ci        }
746cb93a386Sopenharmony_ci
747cb93a386Sopenharmony_ci        dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
748cb93a386Sopenharmony_ci    }
749cb93a386Sopenharmony_ci    return kSuccess;
750cb93a386Sopenharmony_ci}
751cb93a386Sopenharmony_ci
752cb93a386Sopenharmony_ciSkISize SkRawCodec::onGetScaledDimensions(float desiredScale) const {
753cb93a386Sopenharmony_ci    SkASSERT(desiredScale <= 1.f);
754cb93a386Sopenharmony_ci
755cb93a386Sopenharmony_ci    const SkISize dim = this->dimensions();
756cb93a386Sopenharmony_ci    SkASSERT(dim.fWidth != 0 && dim.fHeight != 0);
757cb93a386Sopenharmony_ci
758cb93a386Sopenharmony_ci    if (!fDngImage->isScalable()) {
759cb93a386Sopenharmony_ci        return dim;
760cb93a386Sopenharmony_ci    }
761cb93a386Sopenharmony_ci
762cb93a386Sopenharmony_ci    // Limits the minimum size to be 80 on the short edge.
763cb93a386Sopenharmony_ci    const float shortEdge = static_cast<float>(std::min(dim.fWidth, dim.fHeight));
764cb93a386Sopenharmony_ci    if (desiredScale < 80.f / shortEdge) {
765cb93a386Sopenharmony_ci        desiredScale = 80.f / shortEdge;
766cb93a386Sopenharmony_ci    }
767cb93a386Sopenharmony_ci
768cb93a386Sopenharmony_ci    // For Xtrans images, the integer-factor scaling does not support the half-size scaling case
769cb93a386Sopenharmony_ci    // (stronger downscalings are fine). In this case, returns the factor "3" scaling instead.
770cb93a386Sopenharmony_ci    if (fDngImage->isXtransImage() && desiredScale > 1.f / 3.f && desiredScale < 1.f) {
771cb93a386Sopenharmony_ci        desiredScale = 1.f / 3.f;
772cb93a386Sopenharmony_ci    }
773cb93a386Sopenharmony_ci
774cb93a386Sopenharmony_ci    // Round to integer-factors.
775cb93a386Sopenharmony_ci    const float finalScale = std::floor(1.f/ desiredScale);
776cb93a386Sopenharmony_ci    return SkISize::Make(static_cast<int32_t>(std::floor(dim.fWidth / finalScale)),
777cb93a386Sopenharmony_ci                         static_cast<int32_t>(std::floor(dim.fHeight / finalScale)));
778cb93a386Sopenharmony_ci}
779cb93a386Sopenharmony_ci
780cb93a386Sopenharmony_cibool SkRawCodec::onDimensionsSupported(const SkISize& dim) {
781cb93a386Sopenharmony_ci    const SkISize fullDim = this->dimensions();
782cb93a386Sopenharmony_ci    const float fullShortEdge = static_cast<float>(std::min(fullDim.fWidth, fullDim.fHeight));
783cb93a386Sopenharmony_ci    const float shortEdge = static_cast<float>(std::min(dim.fWidth, dim.fHeight));
784cb93a386Sopenharmony_ci
785cb93a386Sopenharmony_ci    SkISize sizeFloor = this->onGetScaledDimensions(1.f / std::floor(fullShortEdge / shortEdge));
786cb93a386Sopenharmony_ci    SkISize sizeCeil = this->onGetScaledDimensions(1.f / std::ceil(fullShortEdge / shortEdge));
787cb93a386Sopenharmony_ci    return sizeFloor == dim || sizeCeil == dim;
788cb93a386Sopenharmony_ci}
789cb93a386Sopenharmony_ci
790cb93a386Sopenharmony_ciSkRawCodec::~SkRawCodec() {}
791cb93a386Sopenharmony_ci
792cb93a386Sopenharmony_ciSkRawCodec::SkRawCodec(SkDngImage* dngImage)
793cb93a386Sopenharmony_ci    : INHERITED(SkEncodedInfo::Make(dngImage->width(), dngImage->height(),
794cb93a386Sopenharmony_ci                                    SkEncodedInfo::kRGB_Color,
795cb93a386Sopenharmony_ci                                    SkEncodedInfo::kOpaque_Alpha, 8),
796cb93a386Sopenharmony_ci                skcms_PixelFormat_RGBA_8888, nullptr)
797cb93a386Sopenharmony_ci    , fDngImage(dngImage) {}
798