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->initFromPiex() && !dngImage->readDng()) {
    451             return nullptr;
    452         }
    453 
    454         return dngImage.release();
    455     }
    456 
    457     /*
    458      * Renders the DNG image to the size. The DNG SDK only allows scaling close to integer factors
    459      * down to 80 pixels on the short edge. The rendered image will be close to the specified size,
    460      * but there is no guarantee that any of the edges will match the requested size. E.g.
    461      *   100% size:              4000 x 3000
    462      *   requested size:         1600 x 1200
    463      *   returned size could be: 2000 x 1500
    464      */
    465     dng_image* render(int width, int height) {
    466         if (!fHost || !fInfo || !fNegative || !fDngStream) {
    467             if (!this->readDng()) {
    468                 return nullptr;
    469             }
    470         }
    471 
    472         // DNG SDK preserves the aspect ratio, so it only needs to know the longer dimension.
    473         const int preferredSize = SkTMax(width, height);
    474         try {
    475             // render() takes ownership of fHost, fInfo, fNegative and fDngStream when available.
    476             std::unique_ptr<dng_host> host(fHost.release());
    477             std::unique_ptr<dng_info> info(fInfo.release());
    478             std::unique_ptr<dng_negative> negative(fNegative.release());
    479             std::unique_ptr<dng_stream> dngStream(fDngStream.release());
    480 
    481             host->SetPreferredSize(preferredSize);
    482             host->ValidateSizes();
    483 
    484             negative->ReadStage1Image(*host, *dngStream, *info);
    485 
    486             if (info->fMaskIndex != -1) {
    487                 negative->ReadTransparencyMask(*host, *dngStream, *info);
    488             }
    489 
    490             negative->ValidateRawImageDigest(*host);
    491             if (negative->IsDamaged()) {
    492                 return nullptr;
    493             }
    494 
    495             const int32 kMosaicPlane = -1;
    496             negative->BuildStage2Image(*host);
    497             negative->BuildStage3Image(*host, kMosaicPlane);
    498 
    499             dng_render render(*host, *negative);
    500             render.SetFinalSpace(dng_space_sRGB::Get());
    501             render.SetFinalPixelType(ttByte);
    502 
    503             dng_point stage3_size = negative->Stage3Image()->Size();
    504             render.SetMaximumSize(SkTMax(stage3_size.h, stage3_size.v));
    505 
    506             return render.Render();
    507         } catch (...) {
    508             return nullptr;
    509         }
    510     }
    511 
    512     const SkEncodedInfo& getEncodedInfo() const {
    513         return fEncodedInfo;
    514     }
    515 
    516     int width() const {
    517         return fWidth;
    518     }
    519 
    520     int height() const {
    521         return fHeight;
    522     }
    523 
    524     bool isScalable() const {
    525         return fIsScalable;
    526     }
    527 
    528     bool isXtransImage() const {
    529         return fIsXtransImage;
    530     }
    531 
    532     // Quick check if the image contains a valid TIFF header as requested by DNG format.
    533     // Does not affect ownership of stream.
    534     static bool IsTiffHeaderValid(SkRawStream* stream) {
    535         const size_t kHeaderSize = 4;
    536         unsigned char header[kHeaderSize];
    537         if (!stream->read(header, 0 /* offset */, kHeaderSize)) {
    538             return false;
    539         }
    540 
    541         // Check if the header is valid (endian info and magic number "42").
    542         bool littleEndian;
    543         if (!is_valid_endian_marker(header, &littleEndian)) {
    544             return false;
    545         }
    546 
    547         return 0x2A == get_endian_short(header + 2, littleEndian);
    548     }
    549 
    550 private:
    551     bool init(int width, int height, const dng_point& cfaPatternSize) {
    552         fWidth = width;
    553         fHeight = height;
    554 
    555         // The DNG SDK scales only during demosaicing, so scaling is only possible when
    556         // a mosaic info is available.
    557         fIsScalable = cfaPatternSize.v != 0 && cfaPatternSize.h != 0;
    558         fIsXtransImage = fIsScalable ? (cfaPatternSize.v == 6 && cfaPatternSize.h == 6) : false;
    559 
    560         return width > 0 && height > 0;
    561     }
    562 
    563     bool initFromPiex() {
    564         // Does not take the ownership of rawStream.
    565         SkPiexStream piexStream(fStream.get());
    566         ::piex::PreviewImageData imageData;
    567         if (::piex::IsRaw(&piexStream)
    568             && ::piex::GetPreviewImageData(&piexStream, &imageData) == ::piex::Error::kOk)
    569         {
    570             dng_point cfaPatternSize(imageData.cfa_pattern_dim[1], imageData.cfa_pattern_dim[0]);
    571             return this->init(static_cast<int>(imageData.full_width),
    572                               static_cast<int>(imageData.full_height), cfaPatternSize);
    573         }
    574         return false;
    575     }
    576 
    577     bool readDng() {
    578         try {
    579             // Due to the limit of DNG SDK, we need to reset host and info.
    580             fHost.reset(new SkDngHost(&fAllocator));
    581             fInfo.reset(new dng_info);
    582             fDngStream.reset(new SkDngStream(fStream.get()));
    583 
    584             fHost->ValidateSizes();
    585             fInfo->Parse(*fHost, *fDngStream);
    586             fInfo->PostParse(*fHost);
    587             if (!fInfo->IsValidDNG()) {
    588                 return false;
    589             }
    590 
    591             fNegative.reset(fHost->Make_dng_negative());
    592             fNegative->Parse(*fHost, *fDngStream, *fInfo);
    593             fNegative->PostParse(*fHost, *fDngStream, *fInfo);
    594             fNegative->SynchronizeMetadata();
    595 
    596             dng_point cfaPatternSize(0, 0);
    597             if (fNegative->GetMosaicInfo() != nullptr) {
    598                 cfaPatternSize = fNegative->GetMosaicInfo()->fCFAPatternSize;
    599             }
    600             return this->init(static_cast<int>(fNegative->DefaultCropSizeH().As_real64()),
    601                               static_cast<int>(fNegative->DefaultCropSizeV().As_real64()),
    602                               cfaPatternSize);
    603         } catch (...) {
    604             return false;
    605         }
    606     }
    607 
    608     SkDngImage(SkRawStream* stream)
    609         : fStream(stream)
    610         , fEncodedInfo(SkEncodedInfo::Make(SkEncodedInfo::kRGB_Color,
    611                                            SkEncodedInfo::kOpaque_Alpha, 8))
    612     {}
    613 
    614     SkDngMemoryAllocator fAllocator;
    615     std::unique_ptr<SkRawStream> fStream;
    616     std::unique_ptr<dng_host> fHost;
    617     std::unique_ptr<dng_info> fInfo;
    618     std::unique_ptr<dng_negative> fNegative;
    619     std::unique_ptr<dng_stream> fDngStream;
    620 
    621     int fWidth;
    622     int fHeight;
    623     SkEncodedInfo fEncodedInfo;
    624     bool fIsScalable;
    625     bool fIsXtransImage;
    626 };
    627 
    628 /*
    629  * Tries to handle the image with PIEX. If PIEX returns kOk and finds the preview image, create a
    630  * SkJpegCodec. If PIEX returns kFail, then the file is invalid, return nullptr. In other cases,
    631  * fallback to create SkRawCodec for DNG images.
    632  */
    633 SkCodec* SkRawCodec::NewFromStream(SkStream* stream, Result* result) {
    634     std::unique_ptr<SkRawStream> rawStream;
    635     if (is_asset_stream(*stream)) {
    636         rawStream.reset(new SkRawAssetStream(stream));
    637     } else {
    638         rawStream.reset(new SkRawBufferedStream(stream));
    639     }
    640 
    641     // Does not take the ownership of rawStream.
    642     SkPiexStream piexStream(rawStream.get());
    643     ::piex::PreviewImageData imageData;
    644     if (::piex::IsRaw(&piexStream)) {
    645         ::piex::Error error = ::piex::GetPreviewImageData(&piexStream, &imageData);
    646         if (error == ::piex::Error::kFail) {
    647             *result = kInvalidInput;
    648             return nullptr;
    649         }
    650 
    651         sk_sp<SkColorSpace> colorSpace;
    652         switch (imageData.color_space) {
    653             case ::piex::PreviewImageData::kSrgb:
    654                 colorSpace = SkColorSpace::MakeSRGB();
    655                 break;
    656             case ::piex::PreviewImageData::kAdobeRgb:
    657                 colorSpace = SkColorSpace_Base::MakeNamed(SkColorSpace_Base::kAdobeRGB_Named);
    658                 break;
    659         }
    660 
    661         //  Theoretically PIEX can return JPEG compressed image or uncompressed RGB image. We only
    662         //  handle the JPEG compressed preview image here.
    663         if (error == ::piex::Error::kOk && imageData.preview.length > 0 &&
    664             imageData.preview.format == ::piex::Image::kJpegCompressed)
    665         {
    666             // transferBuffer() is destructive to the rawStream. Abandon the rawStream after this
    667             // function call.
    668             // FIXME: one may avoid the copy of memoryStream and use the buffered rawStream.
    669             SkMemoryStream* memoryStream =
    670                 rawStream->transferBuffer(imageData.preview.offset, imageData.preview.length);
    671             if (!memoryStream) {
    672                 *result = kInvalidInput;
    673                 return nullptr;
    674             }
    675             return SkJpegCodec::NewFromStream(memoryStream, result, std::move(colorSpace));
    676         }
    677     }
    678 
    679     if (!SkDngImage::IsTiffHeaderValid(rawStream.get())) {
    680         *result = kUnimplemented;
    681         return nullptr;
    682     }
    683 
    684     // Takes the ownership of the rawStream.
    685     std::unique_ptr<SkDngImage> dngImage(SkDngImage::NewFromStream(rawStream.release()));
    686     if (!dngImage) {
    687         *result = kInvalidInput;
    688         return nullptr;
    689     }
    690 
    691     *result = kSuccess;
    692     return new SkRawCodec(dngImage.release());
    693 }
    694 
    695 SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
    696                                         size_t dstRowBytes, const Options& options,
    697                                         int* rowsDecoded) {
    698     if (!conversion_possible(dstInfo, this->getInfo()) ||
    699         !this->initializeColorXform(dstInfo, options.fPremulBehavior))
    700     {
    701         SkCodecPrintf("Error: cannot convert input type to output type.\n");
    702         return kInvalidConversion;
    703     }
    704 
    705     SkImageInfo swizzlerInfo = dstInfo;
    706     std::unique_ptr<uint32_t[]> xformBuffer = nullptr;
    707     if (this->colorXform()) {
    708         swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType);
    709         xformBuffer.reset(new uint32_t[dstInfo.width()]);
    710     }
    711 
    712     std::unique_ptr<SkSwizzler> swizzler(SkSwizzler::CreateSwizzler(
    713             this->getEncodedInfo(), nullptr, swizzlerInfo, options));
    714     SkASSERT(swizzler);
    715 
    716     const int width = dstInfo.width();
    717     const int height = dstInfo.height();
    718     std::unique_ptr<dng_image> image(fDngImage->render(width, height));
    719     if (!image) {
    720         return kInvalidInput;
    721     }
    722 
    723     // Because the DNG SDK can not guarantee to render to requested size, we allow a small
    724     // difference. Only the overlapping region will be converted.
    725     const float maxDiffRatio = 1.03f;
    726     const dng_point& imageSize = image->Size();
    727     if (imageSize.h / (float) width > maxDiffRatio || imageSize.h < width ||
    728         imageSize.v / (float) height > maxDiffRatio || imageSize.v < height) {
    729         return SkCodec::kInvalidScale;
    730     }
    731 
    732     void* dstRow = dst;
    733     SkAutoTMalloc<uint8_t> srcRow(width * 3);
    734 
    735     dng_pixel_buffer buffer;
    736     buffer.fData = &srcRow[0];
    737     buffer.fPlane = 0;
    738     buffer.fPlanes = 3;
    739     buffer.fColStep = buffer.fPlanes;
    740     buffer.fPlaneStep = 1;
    741     buffer.fPixelType = ttByte;
    742     buffer.fPixelSize = sizeof(uint8_t);
    743     buffer.fRowStep = width * 3;
    744 
    745     for (int i = 0; i < height; ++i) {
    746         buffer.fArea = dng_rect(i, 0, i + 1, width);
    747 
    748         try {
    749             image->Get(buffer, dng_image::edge_zero);
    750         } catch (...) {
    751             *rowsDecoded = i;
    752             return kIncompleteInput;
    753         }
    754 
    755         if (this->colorXform()) {
    756             swizzler->swizzle(xformBuffer.get(), &srcRow[0]);
    757 
    758             this->applyColorXform(dstRow, xformBuffer.get(), dstInfo.width(), kOpaque_SkAlphaType);
    759             dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
    760         } else {
    761             swizzler->swizzle(dstRow, &srcRow[0]);
    762             dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
    763         }
    764     }
    765     return kSuccess;
    766 }
    767 
    768 SkISize SkRawCodec::onGetScaledDimensions(float desiredScale) const {
    769     SkASSERT(desiredScale <= 1.f);
    770 
    771     const SkISize dim = this->getInfo().dimensions();
    772     SkASSERT(dim.fWidth != 0 && dim.fHeight != 0);
    773 
    774     if (!fDngImage->isScalable()) {
    775         return dim;
    776     }
    777 
    778     // Limits the minimum size to be 80 on the short edge.
    779     const float shortEdge = static_cast<float>(SkTMin(dim.fWidth, dim.fHeight));
    780     if (desiredScale < 80.f / shortEdge) {
    781         desiredScale = 80.f / shortEdge;
    782     }
    783 
    784     // For Xtrans images, the integer-factor scaling does not support the half-size scaling case
    785     // (stronger downscalings are fine). In this case, returns the factor "3" scaling instead.
    786     if (fDngImage->isXtransImage() && desiredScale > 1.f / 3.f && desiredScale < 1.f) {
    787         desiredScale = 1.f / 3.f;
    788     }
    789 
    790     // Round to integer-factors.
    791     const float finalScale = std::floor(1.f/ desiredScale);
    792     return SkISize::Make(static_cast<int32_t>(std::floor(dim.fWidth / finalScale)),
    793                          static_cast<int32_t>(std::floor(dim.fHeight / finalScale)));
    794 }
    795 
    796 bool SkRawCodec::onDimensionsSupported(const SkISize& dim) {
    797     const SkISize fullDim = this->getInfo().dimensions();
    798     const float fullShortEdge = static_cast<float>(SkTMin(fullDim.fWidth, fullDim.fHeight));
    799     const float shortEdge = static_cast<float>(SkTMin(dim.fWidth, dim.fHeight));
    800 
    801     SkISize sizeFloor = this->onGetScaledDimensions(1.f / std::floor(fullShortEdge / shortEdge));
    802     SkISize sizeCeil = this->onGetScaledDimensions(1.f / std::ceil(fullShortEdge / shortEdge));
    803     return sizeFloor == dim || sizeCeil == dim;
    804 }
    805 
    806 SkRawCodec::~SkRawCodec() {}
    807 
    808 SkRawCodec::SkRawCodec(SkDngImage* dngImage)
    809     : INHERITED(dngImage->width(), dngImage->height(), dngImage->getEncodedInfo(),
    810                 SkColorSpaceXform::kRGBA_8888_ColorFormat, nullptr,
    811                 SkColorSpace::MakeSRGB())
    812     , fDngImage(dngImage) {}
    813