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