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 SkAndroidCodec_DEFINED 9 #define SkAndroidCodec_DEFINED 10 11 #include "SkCodec.h" 12 #include "SkEncodedImageFormat.h" 13 #include "SkStream.h" 14 #include "SkTypes.h" 15 16 /** 17 * Abstract interface defining image codec functionality that is necessary for 18 * Android. 19 */ 20 class SK_API SkAndroidCodec : SkNoncopyable { 21 public: 22 enum class ExifOrientationBehavior { 23 /** 24 * Ignore any exif orientation markers in the data. 25 * 26 * getInfo's width and height will match the header of the image, and 27 * no processing will be done to match the marker. 28 */ 29 kIgnore, 30 31 /** 32 * Respect the exif orientation marker. 33 * 34 * getInfo's width and height will represent what they should be after 35 * applying the orientation. For example, if the marker specifies a 36 * rotation by 90 degrees, they will be swapped relative to the header. 37 * getAndroidPixels will apply the orientation as well. 38 */ 39 kRespect, 40 }; 41 42 /** 43 * Pass ownership of an SkCodec to a newly-created SkAndroidCodec. 44 */ 45 static std::unique_ptr<SkAndroidCodec> MakeFromCodec(std::unique_ptr<SkCodec>, 46 ExifOrientationBehavior = ExifOrientationBehavior::kIgnore); 47 48 /** 49 * If this stream represents an encoded image that we know how to decode, 50 * return an SkAndroidCodec that can decode it. Otherwise return NULL. 51 * 52 * The SkPngChunkReader handles unknown chunks in PNGs. 53 * See SkCodec.h for more details. 54 * 55 * If NULL is returned, the stream is deleted immediately. Otherwise, the 56 * SkCodec takes ownership of it, and will delete it when done with it. 57 * 58 * ExifOrientationBehavior is set to kIgnore. 59 */ 60 static std::unique_ptr<SkAndroidCodec> MakeFromStream(std::unique_ptr<SkStream>, 61 SkPngChunkReader* = nullptr); 62 63 /** 64 * If this data represents an encoded image that we know how to decode, 65 * return an SkAndroidCodec that can decode it. Otherwise return NULL. 66 * 67 * The SkPngChunkReader handles unknown chunks in PNGs. 68 * See SkCodec.h for more details. 69 * 70 * ExifOrientationBehavior is set to kIgnore. 71 */ 72 static std::unique_ptr<SkAndroidCodec> MakeFromData(sk_sp<SkData>, SkPngChunkReader* = nullptr); 73 74 virtual ~SkAndroidCodec(); 75 getInfo()76 const SkImageInfo& getInfo() const { return fInfo; } 77 78 /** 79 * Format of the encoded data. 80 */ getEncodedFormat()81 SkEncodedImageFormat getEncodedFormat() const { return fCodec->getEncodedFormat(); } 82 83 /** 84 * @param requestedColorType Color type requested by the client 85 * 86 * |requestedColorType| may be overriden. We will default to kF16 87 * for high precision images. 88 * 89 * In the general case, if it is possible to decode to 90 * |requestedColorType|, this returns |requestedColorType|. 91 * Otherwise, this returns a color type that is an appropriate 92 * match for the the encoded data. 93 */ 94 SkColorType computeOutputColorType(SkColorType requestedColorType); 95 96 /** 97 * @param requestedUnpremul Indicates if the client requested 98 * unpremultiplied output 99 * 100 * Returns the appropriate alpha type to decode to. If the image 101 * has alpha, the value of requestedUnpremul will be honored. 102 */ 103 SkAlphaType computeOutputAlphaType(bool requestedUnpremul); 104 105 /** 106 * @param outputColorType Color type that the client will decode to. 107 * @param prefColorSpace Preferred color space to decode to. 108 * This may not return |prefColorSpace| for a couple reasons. 109 * (1) Android Principles: 565 must be sRGB, F16 must be 110 * linear sRGB, transfer function must be parametric. 111 * (2) Codec Limitations: F16 requires a linear color space. 112 * 113 * Returns the appropriate color space to decode to. 114 */ 115 sk_sp<SkColorSpace> computeOutputColorSpace(SkColorType outputColorType, 116 sk_sp<SkColorSpace> prefColorSpace = nullptr); 117 118 /** 119 * Compute the appropriate sample size to get to |size|. 120 * 121 * @param size As an input parameter, the desired output size of 122 * the decode. As an output parameter, the smallest sampled size 123 * larger than the input. 124 * @return the sample size to set AndroidOptions::fSampleSize to decode 125 * to the output |size|. 126 */ 127 int computeSampleSize(SkISize* size) const; 128 129 /** 130 * Returns the dimensions of the scaled output image, for an input 131 * sampleSize. 132 * 133 * When the sample size divides evenly into the original dimensions, the 134 * scaled output dimensions will simply be equal to the original 135 * dimensions divided by the sample size. 136 * 137 * When the sample size does not divide even into the original 138 * dimensions, the codec may round up or down, depending on what is most 139 * efficient to decode. 140 * 141 * Finally, the codec will always recommend a non-zero output, so the output 142 * dimension will always be one if the sampleSize is greater than the 143 * original dimension. 144 */ 145 SkISize getSampledDimensions(int sampleSize) const; 146 147 /** 148 * Return (via desiredSubset) a subset which can decoded from this codec, 149 * or false if the input subset is invalid. 150 * 151 * @param desiredSubset in/out parameter 152 * As input, a desired subset of the original bounds 153 * (as specified by getInfo). 154 * As output, if true is returned, desiredSubset may 155 * have been modified to a subset which is 156 * supported. Although a particular change may have 157 * been made to desiredSubset to create something 158 * supported, it is possible other changes could 159 * result in a valid subset. If false is returned, 160 * desiredSubset's value is undefined. 161 * @return true If the input desiredSubset is valid. 162 * desiredSubset may be modified to a subset 163 * supported by the codec. 164 * false If desiredSubset is invalid (NULL or not fully 165 * contained within the image). 166 */ 167 bool getSupportedSubset(SkIRect* desiredSubset) const; 168 // TODO: Rename SkCodec::getValidSubset() to getSupportedSubset() 169 170 /** 171 * Returns the dimensions of the scaled, partial output image, for an 172 * input sampleSize and subset. 173 * 174 * @param sampleSize Factor to scale down by. 175 * @param subset Must be a valid subset of the original image 176 * dimensions and a subset supported by SkAndroidCodec. 177 * getSubset() can be used to obtain a subset supported 178 * by SkAndroidCodec. 179 * @return Size of the scaled partial image. Or zero size 180 * if either of the inputs is invalid. 181 */ 182 SkISize getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const; 183 184 /** 185 * Additional options to pass to getAndroidPixels(). 186 */ 187 // FIXME: It's a bit redundant to name these AndroidOptions when this class is already 188 // called SkAndroidCodec. On the other hand, it's may be a bit confusing to call 189 // these Options when SkCodec has a slightly different set of Options. Maybe these 190 // should be DecodeOptions or SamplingOptions? 191 struct AndroidOptions { AndroidOptionsAndroidOptions192 AndroidOptions() 193 : fZeroInitialized(SkCodec::kNo_ZeroInitialized) 194 , fSubset(nullptr) 195 , fSampleSize(1) 196 {} 197 198 /** 199 * Indicates is destination pixel memory is zero initialized. 200 * 201 * The default is SkCodec::kNo_ZeroInitialized. 202 */ 203 SkCodec::ZeroInitialized fZeroInitialized; 204 205 /** 206 * If not NULL, represents a subset of the original image to decode. 207 * 208 * Must be within the bounds returned by getInfo(). 209 * 210 * If the EncodedFormat is SkEncodedImageFormat::kWEBP, the top and left 211 * values must be even. 212 * 213 * The default is NULL, meaning a decode of the entire image. 214 */ 215 SkIRect* fSubset; 216 217 /** 218 * The client may provide an integer downscale factor for the decode. 219 * The codec may implement this downscaling by sampling or another 220 * method if it is more efficient. 221 * 222 * The default is 1, representing no downscaling. 223 */ 224 int fSampleSize; 225 }; 226 227 /** 228 * Decode into the given pixels, a block of memory of size at 229 * least (info.fHeight - 1) * rowBytes + (info.fWidth * 230 * bytesPerPixel) 231 * 232 * Repeated calls to this function should give the same results, 233 * allowing the PixelRef to be immutable. 234 * 235 * @param info A description of the format (config, size) 236 * expected by the caller. This can simply be identical 237 * to the info returned by getInfo(). 238 * 239 * This contract also allows the caller to specify 240 * different output-configs, which the implementation can 241 * decide to support or not. 242 * 243 * A size that does not match getInfo() implies a request 244 * to scale or subset. If the codec cannot perform this 245 * scaling or subsetting, it will return an error code. 246 * 247 * The AndroidOptions object is also used to specify any requested scaling or subsetting 248 * using options->fSampleSize and options->fSubset. If NULL, the defaults (as specified above 249 * for AndroidOptions) are used. 250 * 251 * @return Result kSuccess, or another value explaining the type of failure. 252 */ 253 // FIXME: It's a bit redundant to name this getAndroidPixels() when this class is already 254 // called SkAndroidCodec. On the other hand, it's may be a bit confusing to call 255 // this getPixels() when it is a slightly different API than SkCodec's getPixels(). 256 // Maybe this should be decode() or decodeSubset()? 257 SkCodec::Result getAndroidPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, 258 const AndroidOptions* options); 259 260 /** 261 * Simplified version of getAndroidPixels() where we supply the default AndroidOptions as 262 * specified above for AndroidOptions. It will not perform any scaling or subsetting. 263 */ 264 SkCodec::Result getAndroidPixels(const SkImageInfo& info, void* pixels, size_t rowBytes); 265 getPixels(const SkImageInfo & info,void * pixels,size_t rowBytes)266 SkCodec::Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { 267 return this->getAndroidPixels(info, pixels, rowBytes); 268 } 269 codec()270 SkCodec* codec() const { return fCodec.get(); } 271 272 protected: 273 SkAndroidCodec(SkCodec*, ExifOrientationBehavior = ExifOrientationBehavior::kIgnore); 274 275 virtual SkISize onGetSampledDimensions(int sampleSize) const = 0; 276 277 virtual bool onGetSupportedSubset(SkIRect* desiredSubset) const = 0; 278 279 virtual SkCodec::Result onGetAndroidPixels(const SkImageInfo& info, void* pixels, 280 size_t rowBytes, const AndroidOptions& options) = 0; 281 282 private: 283 const SkImageInfo fInfo; 284 const ExifOrientationBehavior fOrientationBehavior; 285 std::unique_ptr<SkCodec> fCodec; 286 }; 287 #endif // SkAndroidCodec_DEFINED 288