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