robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2014 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 "SkColorPriv.h" |
| 9 | #include "SkImageDecoder.h" |
commit-bot@chromium.org | 4c45064 | 2014-05-23 20:00:59 +0000 | [diff] [blame] | 10 | #include "SkScaledBitmapSampler.h" |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 11 | #include "SkStream.h" |
halcanary | 67ec1f8 | 2014-06-27 11:36:20 -0700 | [diff] [blame] | 12 | #include "SkStreamPriv.h" |
krajcevski | e90c900 | 2014-08-05 07:37:26 -0700 | [diff] [blame] | 13 | #include "SkTextureCompressor.h" |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 14 | #include "SkTypes.h" |
| 15 | |
| 16 | #include "etc1.h" |
| 17 | |
| 18 | class SkPKMImageDecoder : public SkImageDecoder { |
| 19 | public: |
| 20 | SkPKMImageDecoder() { } |
| 21 | |
mtklein | 72c9faa | 2015-01-09 10:06:39 -0800 | [diff] [blame] | 22 | Format getFormat() const SK_OVERRIDE { |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 23 | return kPKM_Format; |
| 24 | } |
| 25 | |
| 26 | protected: |
mtklein | 72c9faa | 2015-01-09 10:06:39 -0800 | [diff] [blame] | 27 | Result onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 28 | |
| 29 | private: |
| 30 | typedef SkImageDecoder INHERITED; |
| 31 | }; |
| 32 | |
| 33 | ///////////////////////////////////////////////////////////////////////////////////////// |
| 34 | |
scroggo | 2a12080 | 2014-10-22 12:07:00 -0700 | [diff] [blame] | 35 | SkImageDecoder::Result SkPKMImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 36 | SkAutoMalloc autoMal; |
halcanary | 67ec1f8 | 2014-06-27 11:36:20 -0700 | [diff] [blame] | 37 | const size_t length = SkCopyStreamToStorage(&autoMal, stream); |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 38 | if (0 == length) { |
scroggo | 2a12080 | 2014-10-22 12:07:00 -0700 | [diff] [blame] | 39 | return kFailure; |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 40 | } |
| 41 | |
| 42 | unsigned char* buf = (unsigned char*)autoMal.get(); |
skia.committer@gmail.com | 7693dbf | 2014-05-23 03:03:34 +0000 | [diff] [blame] | 43 | |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 44 | // Make sure original PKM header is there... |
| 45 | SkASSERT(etc1_pkm_is_valid(buf)); |
| 46 | |
| 47 | const unsigned short width = etc1_pkm_get_width(buf); |
| 48 | const unsigned short height = etc1_pkm_get_height(buf); |
| 49 | |
commit-bot@chromium.org | 4c45064 | 2014-05-23 20:00:59 +0000 | [diff] [blame] | 50 | // Setup the sampler... |
| 51 | SkScaledBitmapSampler sampler(width, height, this->getSampleSize()); |
| 52 | |
| 53 | // Set the config... |
reed | 6c22573 | 2014-06-09 19:52:07 -0700 | [diff] [blame] | 54 | bm->setInfo(SkImageInfo::MakeN32(sampler.scaledWidth(), sampler.scaledHeight(), |
| 55 | kOpaque_SkAlphaType)); |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 56 | if (SkImageDecoder::kDecodeBounds_Mode == mode) { |
scroggo | 2a12080 | 2014-10-22 12:07:00 -0700 | [diff] [blame] | 57 | return kSuccess; |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 58 | } |
skia.committer@gmail.com | 7693dbf | 2014-05-23 03:03:34 +0000 | [diff] [blame] | 59 | |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 60 | if (!this->allocPixelRef(bm, NULL)) { |
scroggo | 2a12080 | 2014-10-22 12:07:00 -0700 | [diff] [blame] | 61 | return kFailure; |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 62 | } |
skia.committer@gmail.com | 7693dbf | 2014-05-23 03:03:34 +0000 | [diff] [blame] | 63 | |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 64 | // Lock the pixels, since we're about to write to them... |
| 65 | SkAutoLockPixels alp(*bm); |
skia.committer@gmail.com | 7693dbf | 2014-05-23 03:03:34 +0000 | [diff] [blame] | 66 | |
commit-bot@chromium.org | 4c45064 | 2014-05-23 20:00:59 +0000 | [diff] [blame] | 67 | if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) { |
scroggo | 2a12080 | 2014-10-22 12:07:00 -0700 | [diff] [blame] | 68 | return kFailure; |
commit-bot@chromium.org | 4c45064 | 2014-05-23 20:00:59 +0000 | [diff] [blame] | 69 | } |
| 70 | |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 71 | // Advance buffer past the header |
| 72 | buf += ETC_PKM_HEADER_SIZE; |
skia.committer@gmail.com | 7693dbf | 2014-05-23 03:03:34 +0000 | [diff] [blame] | 73 | |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 74 | // ETC1 Data is encoded as RGB pixels, so we should extract it as such |
| 75 | int nPixels = width * height; |
| 76 | SkAutoMalloc outRGBData(nPixels * 3); |
krajcevski | e90c900 | 2014-08-05 07:37:26 -0700 | [diff] [blame] | 77 | uint8_t *outRGBDataPtr = reinterpret_cast<uint8_t *>(outRGBData.get()); |
skia.committer@gmail.com | 7693dbf | 2014-05-23 03:03:34 +0000 | [diff] [blame] | 78 | |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 79 | // Decode ETC1 |
krajcevski | e90c900 | 2014-08-05 07:37:26 -0700 | [diff] [blame] | 80 | if (!SkTextureCompressor::DecompressBufferFromFormat( |
| 81 | outRGBDataPtr, width*3, buf, width, height, SkTextureCompressor::kETC1_Format)) { |
scroggo | 2a12080 | 2014-10-22 12:07:00 -0700 | [diff] [blame] | 82 | return kFailure; |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 83 | } |
| 84 | |
| 85 | // Set each of the pixels... |
commit-bot@chromium.org | 4c45064 | 2014-05-23 20:00:59 +0000 | [diff] [blame] | 86 | const int srcRowBytes = width * 3; |
| 87 | const int dstHeight = sampler.scaledHeight(); |
| 88 | const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr); |
| 89 | srcRow += sampler.srcY0() * srcRowBytes; |
| 90 | for (int y = 0; y < dstHeight; ++y) { |
| 91 | sampler.next(srcRow); |
| 92 | srcRow += sampler.srcDY() * srcRowBytes; |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 93 | } |
skia.committer@gmail.com | 7693dbf | 2014-05-23 03:03:34 +0000 | [diff] [blame] | 94 | |
scroggo | 2a12080 | 2014-10-22 12:07:00 -0700 | [diff] [blame] | 95 | return kSuccess; |
robertphillips@google.com | 8cf81e0 | 2014-05-22 18:40:29 +0000 | [diff] [blame] | 96 | } |
| 97 | |
| 98 | ///////////////////////////////////////////////////////////////////////////////////////// |
| 99 | DEFINE_DECODER_CREATOR(PKMImageDecoder); |
| 100 | ///////////////////////////////////////////////////////////////////////////////////////// |
| 101 | |
| 102 | static bool is_pkm(SkStreamRewindable* stream) { |
| 103 | // Read the PKM header and make sure it's valid. |
| 104 | unsigned char buf[ETC_PKM_HEADER_SIZE]; |
| 105 | if (stream->read((void*)buf, ETC_PKM_HEADER_SIZE) != ETC_PKM_HEADER_SIZE) { |
| 106 | return false; |
| 107 | } |
| 108 | |
| 109 | return SkToBool(etc1_pkm_is_valid(buf)); |
| 110 | } |
| 111 | |
| 112 | static SkImageDecoder* sk_libpkm_dfactory(SkStreamRewindable* stream) { |
| 113 | if (is_pkm(stream)) { |
| 114 | return SkNEW(SkPKMImageDecoder); |
| 115 | } |
| 116 | return NULL; |
| 117 | } |
| 118 | |
| 119 | static SkImageDecoder_DecodeReg gReg(sk_libpkm_dfactory); |
| 120 | |
| 121 | static SkImageDecoder::Format get_format_pkm(SkStreamRewindable* stream) { |
| 122 | if (is_pkm(stream)) { |
| 123 | return SkImageDecoder::kPKM_Format; |
| 124 | } |
| 125 | return SkImageDecoder::kUnknown_Format; |
| 126 | } |
| 127 | |
| 128 | static SkImageDecoder_FormatReg gFormatReg(get_format_pkm); |