• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 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 "SkWbmpCodec.h"
9 
10 #include "SkCodec.h"
11 #include "SkCodecPriv.h"
12 #include "SkColorData.h"
13 #include "SkColorTable.h"
14 #include "SkData.h"
15 #include "SkStream.h"
16 #include "SkTo.h"
17 
18 // Each bit represents a pixel, so width is actually a number of bits.
19 // A row will always be stored in bytes, so we round width up to the
20 // nearest multiple of 8 to get the number of bits actually in the row.
21 // We then divide by 8 to convert to bytes.
get_src_row_bytes(int width)22 static inline size_t get_src_row_bytes(int width) {
23     return SkAlign8(width) >> 3;
24 }
25 
valid_color_type(const SkImageInfo & dstInfo)26 static inline bool valid_color_type(const SkImageInfo& dstInfo) {
27     switch (dstInfo.colorType()) {
28         case kRGBA_8888_SkColorType:
29         case kBGRA_8888_SkColorType:
30         case kGray_8_SkColorType:
31         case kRGB_565_SkColorType:
32             return true;
33         case kRGBA_F16_SkColorType:
34             return dstInfo.colorSpace();
35         default:
36             return false;
37     }
38 }
39 
read_byte(SkStream * stream,uint8_t * data)40 static bool read_byte(SkStream* stream, uint8_t* data)
41 {
42     return stream->read(data, 1) == 1;
43 }
44 
45 // http://en.wikipedia.org/wiki/Variable-length_quantity
read_mbf(SkStream * stream,uint64_t * value)46 static bool read_mbf(SkStream* stream, uint64_t* value) {
47     uint64_t n = 0;
48     uint8_t data;
49     const uint64_t kLimit = 0xFE00000000000000;
50     SkASSERT(kLimit == ~((~static_cast<uint64_t>(0)) >> 7));
51     do {
52         if (n & kLimit) { // Will overflow on shift by 7.
53             return false;
54         }
55         if (stream->read(&data, 1) != 1) {
56             return false;
57         }
58         n = (n << 7) | (data & 0x7F);
59     } while (data & 0x80);
60     *value = n;
61     return true;
62 }
63 
read_header(SkStream * stream,SkISize * size)64 static bool read_header(SkStream* stream, SkISize* size) {
65     {
66         uint8_t data;
67         if (!read_byte(stream, &data) || data != 0) { // unknown type
68             return false;
69         }
70         if (!read_byte(stream, &data) || (data & 0x9F)) { // skip fixed header
71             return false;
72         }
73     }
74 
75     uint64_t width, height;
76     if (!read_mbf(stream, &width) || width > 0xFFFF || !width) {
77         return false;
78     }
79     if (!read_mbf(stream, &height) || height > 0xFFFF || !height) {
80         return false;
81     }
82     if (size) {
83         *size = SkISize::Make(SkToS32(width), SkToS32(height));
84     }
85     return true;
86 }
87 
onRewind()88 bool SkWbmpCodec::onRewind() {
89     return read_header(this->stream(), nullptr);
90 }
91 
readRow(uint8_t * row)92 bool SkWbmpCodec::readRow(uint8_t* row) {
93     return this->stream()->read(row, fSrcRowBytes) == fSrcRowBytes;
94 }
95 
SkWbmpCodec(SkEncodedInfo && info,std::unique_ptr<SkStream> stream)96 SkWbmpCodec::SkWbmpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream)
97     // Wbmp does not need a colorXform, so choose an arbitrary srcFormat.
98     : INHERITED(std::move(info), skcms_PixelFormat(),
99                 std::move(stream))
100     , fSrcRowBytes(get_src_row_bytes(this->dimensions().width()))
101     , fSwizzler(nullptr)
102 {}
103 
onGetEncodedFormat() const104 SkEncodedImageFormat SkWbmpCodec::onGetEncodedFormat() const {
105     return SkEncodedImageFormat::kWBMP;
106 }
107 
conversionSupported(const SkImageInfo & dst,bool srcIsOpaque,bool)108 bool SkWbmpCodec::conversionSupported(const SkImageInfo& dst, bool srcIsOpaque,
109                                       bool /*needsColorXform*/) {
110     return valid_color_type(dst) && valid_alpha(dst.alphaType(), srcIsOpaque);
111 }
112 
onGetPixels(const SkImageInfo & info,void * dst,size_t rowBytes,const Options & options,int * rowsDecoded)113 SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info,
114                                          void* dst,
115                                          size_t rowBytes,
116                                          const Options& options,
117                                          int* rowsDecoded) {
118     if (options.fSubset) {
119         // Subsets are not supported.
120         return kUnimplemented;
121     }
122 
123     // Initialize the swizzler
124     std::unique_ptr<SkSwizzler> swizzler = SkSwizzler::Make(this->getEncodedInfo(), nullptr, info,
125                                                             options);
126     SkASSERT(swizzler);
127 
128     // Perform the decode
129     SkISize size = info.dimensions();
130     SkAutoTMalloc<uint8_t> src(fSrcRowBytes);
131     void* dstRow = dst;
132     for (int y = 0; y < size.height(); ++y) {
133         if (!this->readRow(src.get())) {
134             *rowsDecoded = y;
135             return kIncompleteInput;
136         }
137         swizzler->swizzle(dstRow, src.get());
138         dstRow = SkTAddOffset<void>(dstRow, rowBytes);
139     }
140     return kSuccess;
141 }
142 
IsWbmp(const void * buffer,size_t bytesRead)143 bool SkWbmpCodec::IsWbmp(const void* buffer, size_t bytesRead) {
144     SkMemoryStream stream(buffer, bytesRead, false);
145     return read_header(&stream, nullptr);
146 }
147 
MakeFromStream(std::unique_ptr<SkStream> stream,Result * result)148 std::unique_ptr<SkCodec> SkWbmpCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
149                                                      Result* result) {
150     SkISize size;
151     if (!read_header(stream.get(), &size)) {
152         // This already succeeded in IsWbmp, so this stream was corrupted in/
153         // after rewind.
154         *result = kCouldNotRewind;
155         return nullptr;
156     }
157     *result = kSuccess;
158     auto info = SkEncodedInfo::Make(size.width(), size.height(), SkEncodedInfo::kGray_Color,
159                                     SkEncodedInfo::kOpaque_Alpha, 1);
160     return std::unique_ptr<SkCodec>(new SkWbmpCodec(std::move(info), std::move(stream)));
161 }
162 
onGetScanlines(void * dst,int count,size_t dstRowBytes)163 int SkWbmpCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
164     void* dstRow = dst;
165     for (int y = 0; y < count; ++y) {
166         if (!this->readRow(fSrcBuffer.get())) {
167             return y;
168         }
169         fSwizzler->swizzle(dstRow, fSrcBuffer.get());
170         dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
171     }
172     return count;
173 }
174 
onSkipScanlines(int count)175 bool SkWbmpCodec::onSkipScanlines(int count) {
176     const size_t bytesToSkip = count * fSrcRowBytes;
177     return this->stream()->skip(bytesToSkip) == bytesToSkip;
178 }
179 
onStartScanlineDecode(const SkImageInfo & dstInfo,const Options & options)180 SkCodec::Result SkWbmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
181         const Options& options) {
182     if (options.fSubset) {
183         // Subsets are not supported.
184         return kUnimplemented;
185     }
186 
187     fSwizzler = SkSwizzler::Make(this->getEncodedInfo(), nullptr, dstInfo, options);
188     SkASSERT(fSwizzler);
189 
190     fSrcBuffer.reset(fSrcRowBytes);
191 
192     return kSuccess;
193 }
194