scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 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 | #ifndef SkCodec_DEFINED |
| 9 | #define SkCodec_DEFINED |
| 10 | |
scroggo | eb602a5 | 2015-07-09 08:16:03 -0700 | [diff] [blame^] | 11 | #include "SkColor.h" |
scroggo | 1dd3ea9 | 2015-03-20 11:55:55 -0700 | [diff] [blame] | 12 | #include "SkEncodedFormat.h" |
scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 13 | #include "SkImageInfo.h" |
| 14 | #include "SkSize.h" |
scroggo | fffeede | 2015-03-18 10:50:37 -0700 | [diff] [blame] | 15 | #include "SkStream.h" |
scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 16 | #include "SkTemplates.h" |
| 17 | #include "SkTypes.h" |
| 18 | |
| 19 | class SkData; |
scroggo | eb602a5 | 2015-07-09 08:16:03 -0700 | [diff] [blame^] | 20 | class SkScanlineDecoder; |
scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 21 | |
| 22 | /** |
| 23 | * Abstraction layer directly on top of an image codec. |
| 24 | */ |
scroggo | eb602a5 | 2015-07-09 08:16:03 -0700 | [diff] [blame^] | 25 | class SkCodec : SkNoncopyable { |
scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 26 | public: |
| 27 | /** |
| 28 | * If this stream represents an encoded image that we know how to decode, |
| 29 | * return an SkCodec that can decode it. Otherwise return NULL. |
| 30 | * |
| 31 | * If NULL is returned, the stream is deleted immediately. Otherwise, the |
| 32 | * SkCodec takes ownership of it, and will delete it when done with it. |
| 33 | */ |
| 34 | static SkCodec* NewFromStream(SkStream*); |
| 35 | |
| 36 | /** |
| 37 | * If this data represents an encoded image that we know how to decode, |
| 38 | * return an SkCodec that can decode it. Otherwise return NULL. |
| 39 | * |
| 40 | * Will take a ref if it returns a codec, else will not affect the data. |
| 41 | */ |
| 42 | static SkCodec* NewFromData(SkData*); |
| 43 | |
scroggo | eb602a5 | 2015-07-09 08:16:03 -0700 | [diff] [blame^] | 44 | virtual ~SkCodec(); |
| 45 | |
| 46 | /** |
| 47 | * Return the ImageInfo associated with this codec. |
| 48 | */ |
| 49 | const SkImageInfo& getInfo() const { return fInfo; } |
| 50 | |
scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 51 | /** |
| 52 | * Return a size that approximately supports the desired scale factor. |
| 53 | * The codec may not be able to scale efficiently to the exact scale |
| 54 | * factor requested, so return a size that approximates that scale. |
scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 55 | */ |
scroggo | fffeede | 2015-03-18 10:50:37 -0700 | [diff] [blame] | 56 | SkISize getScaledDimensions(float desiredScale) const { |
| 57 | return this->onGetScaledDimensions(desiredScale); |
| 58 | } |
scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 59 | |
scroggo | 1dd3ea9 | 2015-03-20 11:55:55 -0700 | [diff] [blame] | 60 | /** |
| 61 | * Format of the encoded data. |
| 62 | */ |
| 63 | SkEncodedFormat getEncodedFormat() const { return this->onGetEncodedFormat(); } |
| 64 | |
scroggo | 0524590 | 2015-03-25 11:11:52 -0700 | [diff] [blame] | 65 | /** |
scroggo | eb602a5 | 2015-07-09 08:16:03 -0700 | [diff] [blame^] | 66 | * Used to describe the result of a call to getPixels(). |
| 67 | * |
| 68 | * Result is the union of possible results from subclasses. |
| 69 | */ |
| 70 | enum Result { |
| 71 | /** |
| 72 | * General return value for success. |
| 73 | */ |
| 74 | kSuccess, |
| 75 | /** |
| 76 | * The input is incomplete. A partial image was generated. |
| 77 | */ |
| 78 | kIncompleteInput, |
| 79 | /** |
| 80 | * The generator cannot convert to match the request, ignoring |
| 81 | * dimensions. |
| 82 | */ |
| 83 | kInvalidConversion, |
| 84 | /** |
| 85 | * The generator cannot scale to requested size. |
| 86 | */ |
| 87 | kInvalidScale, |
| 88 | /** |
| 89 | * Parameters (besides info) are invalid. e.g. NULL pixels, rowBytes |
| 90 | * too small, etc. |
| 91 | */ |
| 92 | kInvalidParameters, |
| 93 | /** |
| 94 | * The input did not contain a valid image. |
| 95 | */ |
| 96 | kInvalidInput, |
| 97 | /** |
| 98 | * Fulfilling this request requires rewinding the input, which is not |
| 99 | * supported for this input. |
| 100 | */ |
| 101 | kCouldNotRewind, |
| 102 | /** |
| 103 | * This method is not implemented by this generator. |
| 104 | */ |
| 105 | kUnimplemented, |
| 106 | }; |
| 107 | |
| 108 | /** |
| 109 | * Whether or not the memory passed to getPixels is zero initialized. |
| 110 | */ |
| 111 | enum ZeroInitialized { |
| 112 | /** |
| 113 | * The memory passed to getPixels is zero initialized. The SkCodec |
| 114 | * may take advantage of this by skipping writing zeroes. |
| 115 | */ |
| 116 | kYes_ZeroInitialized, |
| 117 | /** |
| 118 | * The memory passed to getPixels has not been initialized to zero, |
| 119 | * so the SkCodec must write all zeroes to memory. |
| 120 | * |
| 121 | * This is the default. It will be used if no Options struct is used. |
| 122 | */ |
| 123 | kNo_ZeroInitialized, |
| 124 | }; |
| 125 | |
| 126 | /** |
| 127 | * Additional options to pass to getPixels. |
| 128 | */ |
| 129 | struct Options { |
| 130 | Options() |
| 131 | : fZeroInitialized(kNo_ZeroInitialized) {} |
| 132 | |
| 133 | ZeroInitialized fZeroInitialized; |
| 134 | }; |
| 135 | |
| 136 | /** |
| 137 | * Decode into the given pixels, a block of memory of size at |
| 138 | * least (info.fHeight - 1) * rowBytes + (info.fWidth * |
| 139 | * bytesPerPixel) |
| 140 | * |
| 141 | * Repeated calls to this function should give the same results, |
| 142 | * allowing the PixelRef to be immutable. |
| 143 | * |
| 144 | * @param info A description of the format (config, size) |
| 145 | * expected by the caller. This can simply be identical |
| 146 | * to the info returned by getInfo(). |
| 147 | * |
| 148 | * This contract also allows the caller to specify |
| 149 | * different output-configs, which the implementation can |
| 150 | * decide to support or not. |
| 151 | * |
| 152 | * A size that does not match getInfo() implies a request |
| 153 | * to scale. If the generator cannot perform this scale, |
| 154 | * it will return kInvalidScale. |
| 155 | * |
| 156 | * If info is kIndex8_SkColorType, then the caller must provide storage for up to 256 |
| 157 | * SkPMColor values in ctable. On success the generator must copy N colors into that storage, |
| 158 | * (where N is the logical number of table entries) and set ctableCount to N. |
| 159 | * |
| 160 | * If info is not kIndex8_SkColorType, then the last two parameters may be NULL. If ctableCount |
| 161 | * is not null, it will be set to 0. |
| 162 | * |
| 163 | * @return Result kSuccess, or another value explaining the type of failure. |
| 164 | */ |
| 165 | Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options*, |
| 166 | SkPMColor ctable[], int* ctableCount); |
| 167 | |
| 168 | /** |
| 169 | * Simplified version of getPixels() that asserts that info is NOT kIndex8_SkColorType and |
| 170 | * uses the default Options. |
| 171 | */ |
| 172 | Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes); |
| 173 | |
| 174 | /** |
scroggo | 0524590 | 2015-03-25 11:11:52 -0700 | [diff] [blame] | 175 | * Return an object which can be used to decode individual scanlines. |
| 176 | * |
| 177 | * This object is owned by the SkCodec, which will handle its lifetime. The |
| 178 | * returned object is only valid until the SkCodec is deleted or the next |
| 179 | * call to getScanlineDecoder, whichever comes first. |
| 180 | * |
| 181 | * Calling a second time will rewind and replace the existing one with a |
| 182 | * new one. If the stream cannot be rewound, this will delete the existing |
| 183 | * one and return NULL. |
| 184 | * |
| 185 | * @param dstInfo Info of the destination. If the dimensions do not match |
| 186 | * those of getInfo, this implies a scale. |
msarett | 9e43cab | 2015-04-29 07:38:43 -0700 | [diff] [blame] | 187 | * @param options Contains decoding options, including if memory is zero |
| 188 | * initialized. |
| 189 | * @param ctable A pointer to a color table. When dstInfo.colorType() is |
| 190 | * kIndex8, this should be non-NULL and have enough storage for 256 |
| 191 | * colors. The color table will be populated after decoding the palette. |
| 192 | * @param ctableCount A pointer to the size of the color table. When |
| 193 | * dstInfo.colorType() is kIndex8, this should be non-NULL. It will |
| 194 | * be modified to the true size of the color table (<= 256) after |
| 195 | * decoding the palette. |
scroggo | 0524590 | 2015-03-25 11:11:52 -0700 | [diff] [blame] | 196 | * @return New SkScanlineDecoder, or NULL on failure. |
| 197 | * |
| 198 | * NOTE: If any rows were previously decoded, this requires rewinding the |
| 199 | * SkStream. |
| 200 | * |
| 201 | * NOTE: The scanline decoder is owned by the SkCodec and will delete it |
| 202 | * when the SkCodec is deleted. |
| 203 | */ |
msarett | 9e43cab | 2015-04-29 07:38:43 -0700 | [diff] [blame] | 204 | SkScanlineDecoder* getScanlineDecoder(const SkImageInfo& dstInfo, const Options* options, |
| 205 | SkPMColor ctable[], int* ctableCount); |
| 206 | |
| 207 | /** |
| 208 | * Simplified version of getScanlineDecoder() that asserts that info is NOT |
| 209 | * kIndex8_SkColorType and uses the default Options. |
| 210 | */ |
scroggo | 0524590 | 2015-03-25 11:11:52 -0700 | [diff] [blame] | 211 | SkScanlineDecoder* getScanlineDecoder(const SkImageInfo& dstInfo); |
| 212 | |
| 213 | /** |
| 214 | * Some images may initially report that they have alpha due to the format |
| 215 | * of the encoded data, but then never use any colors which have alpha |
| 216 | * less than 100%. This function can be called *after* decoding to |
| 217 | * determine if such an image truly had alpha. Calling it before decoding |
| 218 | * is undefined. |
| 219 | * FIXME: see skbug.com/3582. |
| 220 | */ |
| 221 | bool reallyHasAlpha() const { |
| 222 | return this->onReallyHasAlpha(); |
| 223 | } |
| 224 | |
scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 225 | protected: |
| 226 | SkCodec(const SkImageInfo&, SkStream*); |
| 227 | |
scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 228 | virtual SkISize onGetScaledDimensions(float /* desiredScale */) const { |
| 229 | // By default, scaling is not supported. |
halcanary | b880d7f | 2015-03-26 06:29:03 -0700 | [diff] [blame] | 230 | return this->getInfo().dimensions(); |
scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 231 | } |
| 232 | |
scroggo | 1dd3ea9 | 2015-03-20 11:55:55 -0700 | [diff] [blame] | 233 | virtual SkEncodedFormat onGetEncodedFormat() const = 0; |
| 234 | |
scroggo | eb602a5 | 2015-07-09 08:16:03 -0700 | [diff] [blame^] | 235 | virtual Result onGetPixels(const SkImageInfo& info, |
| 236 | void* pixels, size_t rowBytes, const Options&, |
| 237 | SkPMColor ctable[], int* ctableCount) = 0; |
| 238 | |
scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 239 | /** |
scroggo | 0524590 | 2015-03-25 11:11:52 -0700 | [diff] [blame] | 240 | * Override if your codec supports scanline decoding. |
| 241 | * |
scroggo | 5842154 | 2015-04-01 11:25:20 -0700 | [diff] [blame] | 242 | * As in onGetPixels(), the implementation must call rewindIfNeeded() and |
| 243 | * handle as appropriate. |
scroggo | 0524590 | 2015-03-25 11:11:52 -0700 | [diff] [blame] | 244 | * |
| 245 | * @param dstInfo Info of the destination. If the dimensions do not match |
| 246 | * those of getInfo, this implies a scale. |
msarett | 9e43cab | 2015-04-29 07:38:43 -0700 | [diff] [blame] | 247 | * @param options Contains decoding options, including if memory is zero |
| 248 | * initialized. |
| 249 | * @param ctable A pointer to a color table. When dstInfo.colorType() is |
| 250 | * kIndex8, this should be non-NULL and have enough storage for 256 |
| 251 | * colors. The color table will be populated after decoding the palette. |
| 252 | * @param ctableCount A pointer to the size of the color table. When |
| 253 | * dstInfo.colorType() is kIndex8, this should be non-NULL. It will |
| 254 | * be modified to the true size of the color table (<= 256) after |
| 255 | * decoding the palette. |
scroggo | 0524590 | 2015-03-25 11:11:52 -0700 | [diff] [blame] | 256 | * @return New SkScanlineDecoder on success, NULL otherwise. The SkCodec |
| 257 | * will take ownership of the returned scanline decoder. |
| 258 | */ |
msarett | 9e43cab | 2015-04-29 07:38:43 -0700 | [diff] [blame] | 259 | virtual SkScanlineDecoder* onGetScanlineDecoder(const SkImageInfo& dstInfo, |
| 260 | const Options& options, |
| 261 | SkPMColor ctable[], |
| 262 | int* ctableCount) { |
scroggo | 0524590 | 2015-03-25 11:11:52 -0700 | [diff] [blame] | 263 | return NULL; |
| 264 | } |
| 265 | |
| 266 | virtual bool onReallyHasAlpha() const { return false; } |
| 267 | |
halcanary | a096d7a | 2015-03-27 12:16:53 -0700 | [diff] [blame] | 268 | enum RewindState { |
| 269 | kRewound_RewindState, |
| 270 | kNoRewindNecessary_RewindState, |
| 271 | kCouldNotRewind_RewindState |
| 272 | }; |
scroggo | 0524590 | 2015-03-25 11:11:52 -0700 | [diff] [blame] | 273 | /** |
scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 274 | * If the stream was previously read, attempt to rewind. |
| 275 | * @returns: |
halcanary | a096d7a | 2015-03-27 12:16:53 -0700 | [diff] [blame] | 276 | * kRewound if the stream needed to be rewound, and the |
| 277 | * rewind succeeded. |
| 278 | * kNoRewindNecessary if the stream did not need to be |
| 279 | * rewound. |
| 280 | * kCouldNotRewind if the stream needed to be rewound, and |
| 281 | * rewind failed. |
| 282 | * |
scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 283 | * Subclasses MUST call this function before reading the stream (e.g. in |
| 284 | * onGetPixels). If it returns false, onGetPixels should return |
| 285 | * kCouldNotRewind. |
| 286 | */ |
halcanary | a096d7a | 2015-03-27 12:16:53 -0700 | [diff] [blame] | 287 | RewindState SK_WARN_UNUSED_RESULT rewindIfNeeded(); |
scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 288 | |
msarett | c0e80c1 | 2015-07-01 06:50:35 -0700 | [diff] [blame] | 289 | /** |
msarett | 7411438 | 2015-03-16 11:55:18 -0700 | [diff] [blame] | 290 | * Get method for the input stream |
msarett | 7411438 | 2015-03-16 11:55:18 -0700 | [diff] [blame] | 291 | */ |
| 292 | SkStream* stream() { |
| 293 | return fStream.get(); |
| 294 | } |
| 295 | |
msarett | c0e80c1 | 2015-07-01 06:50:35 -0700 | [diff] [blame] | 296 | /** |
| 297 | * If the codec has a scanline decoder, return it (no ownership change occurs) |
| 298 | * else return NULL. |
| 299 | * The returned decoder is valid while the codec exists and the client has not |
| 300 | * created a new scanline decoder. |
| 301 | */ |
| 302 | SkScanlineDecoder* scanlineDecoder() { |
scroggo | eb602a5 | 2015-07-09 08:16:03 -0700 | [diff] [blame^] | 303 | return fScanlineDecoder; |
msarett | c0e80c1 | 2015-07-01 06:50:35 -0700 | [diff] [blame] | 304 | } |
| 305 | |
| 306 | /** |
| 307 | * Allow the codec subclass to detach and take ownership of the scanline decoder. |
| 308 | * This will likely be used when the scanline decoder needs to be destroyed |
| 309 | * in the destructor of the subclass. |
| 310 | */ |
| 311 | SkScanlineDecoder* detachScanlineDecoder() { |
scroggo | eb602a5 | 2015-07-09 08:16:03 -0700 | [diff] [blame^] | 312 | SkScanlineDecoder* scanlineDecoder = fScanlineDecoder; |
| 313 | fScanlineDecoder = NULL; |
| 314 | return scanlineDecoder; |
msarett | c0e80c1 | 2015-07-01 06:50:35 -0700 | [diff] [blame] | 315 | } |
| 316 | |
scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 317 | private: |
scroggo | eb602a5 | 2015-07-09 08:16:03 -0700 | [diff] [blame^] | 318 | const SkImageInfo fInfo; |
| 319 | SkAutoTDelete<SkStream> fStream; |
| 320 | bool fNeedsRewind; |
| 321 | SkScanlineDecoder* fScanlineDecoder; |
scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 322 | }; |
| 323 | #endif // SkCodec_DEFINED |