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