1 /* 2 * Copyright 2015 The Android Open Source Project 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 SkCodecPriv_DEFINED 9 #define SkCodecPriv_DEFINED 10 11 #include "SkColorPriv.h" 12 #include "SkColorTable.h" 13 #include "SkImageInfo.h" 14 #include "SkTypes.h" 15 16 #ifdef SK_PRINT_CODEC_MESSAGES 17 #define SkCodecPrintf SkDebugf 18 #else 19 #define SkCodecPrintf(...) 20 #endif 21 22 // FIXME: Consider sharing with dm, nanbench, and tools. 23 inline float get_scale_from_sample_size(int sampleSize) { 24 return 1.0f / ((float) sampleSize); 25 } 26 27 inline bool is_valid_subset(const SkIRect& subset, const SkISize& imageDims) { 28 return SkIRect::MakeSize(imageDims).contains(subset); 29 } 30 31 /* 32 * returns a scaled dimension based on the original dimension and the sampleSize 33 * NOTE: we round down here for scaled dimension to match the behavior of SkImageDecoder 34 * FIXME: I think we should call this get_sampled_dimension(). 35 */ 36 inline int get_scaled_dimension(int srcDimension, int sampleSize) { 37 if (sampleSize > srcDimension) { 38 return 1; 39 } 40 return srcDimension / sampleSize; 41 } 42 43 /* 44 * Returns the first coordinate that we will keep during a scaled decode. 45 * The output can be interpreted as an x-coordinate or a y-coordinate. 46 * 47 * This does not need to be called and is not called when sampleFactor == 1. 48 */ 49 inline int get_start_coord(int sampleFactor) { return sampleFactor / 2; }; 50 51 /* 52 * Given a coordinate in the original image, this returns the corresponding 53 * coordinate in the scaled image. This function is meaningless if 54 * IsCoordNecessary returns false. 55 * The output can be interpreted as an x-coordinate or a y-coordinate. 56 * 57 * This does not need to be called and is not called when sampleFactor == 1. 58 */ 59 inline int get_dst_coord(int srcCoord, int sampleFactor) { return srcCoord / sampleFactor; }; 60 61 /* 62 * When scaling, we will discard certain y-coordinates (rows) and 63 * x-coordinates (columns). This function returns true if we should keep the 64 * coordinate and false otherwise. 65 * The inputs may be x-coordinates or y-coordinates. 66 * 67 * This does not need to be called and is not called when sampleFactor == 1. 68 */ 69 inline bool is_coord_necessary(int srcCoord, int sampleFactor, int scaledDim) { 70 // Get the first coordinate that we want to keep 71 int startCoord = get_start_coord(sampleFactor); 72 73 // Return false on edge cases 74 if (srcCoord < startCoord || get_dst_coord(srcCoord, sampleFactor) >= scaledDim) { 75 return false; 76 } 77 78 // Every sampleFactor rows are necessary 79 return ((srcCoord - startCoord) % sampleFactor) == 0; 80 } 81 82 inline bool valid_alpha(SkAlphaType dstAlpha, SkAlphaType srcAlpha) { 83 if (kUnknown_SkAlphaType == dstAlpha) { 84 return false; 85 } 86 87 if (srcAlpha != dstAlpha) { 88 if (kOpaque_SkAlphaType == srcAlpha) { 89 // If the source is opaque, we can support any. 90 SkCodecPrintf("Warning: an opaque image should be decoded as opaque " 91 "- it is being decoded as non-opaque, which will draw slower\n"); 92 return true; 93 } 94 95 // The source is not opaque 96 switch (dstAlpha) { 97 case kPremul_SkAlphaType: 98 case kUnpremul_SkAlphaType: 99 // The source is not opaque, so either of these is okay 100 break; 101 default: 102 // We cannot decode a non-opaque image to opaque (or unknown) 103 return false; 104 } 105 } 106 return true; 107 } 108 109 /* 110 * Most of our codecs support the same conversions: 111 * - profileType must be the same 112 * - opaque to any alpha type 113 * - 565 only if opaque 114 * - premul to unpremul and vice versa 115 * - always support N32 116 * - otherwise match the src color type 117 */ 118 inline bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) { 119 // FIXME: skbug.com/4895 120 // Currently, we treat both kLinear and ksRGB encoded images as if they are kLinear. 121 // This makes sense while we do not have proper support for ksRGB. This is also 122 // the reason why we always allow the client to request kLinear. 123 if (dst.profileType() != src.profileType() && 124 kLinear_SkColorProfileType != dst.profileType()) { 125 return false; 126 } 127 128 // Ensure the alpha type is valid 129 if (!valid_alpha(dst.alphaType(), src.alphaType())) { 130 return false; 131 } 132 133 // Check for supported color types 134 switch (dst.colorType()) { 135 case kN32_SkColorType: 136 return true; 137 case kRGB_565_SkColorType: 138 return kOpaque_SkAlphaType == dst.alphaType(); 139 case kGray_8_SkColorType: 140 if (kOpaque_SkAlphaType != dst.alphaType()) { 141 return false; 142 } 143 // Fall through 144 default: 145 return dst.colorType() == src.colorType(); 146 } 147 } 148 149 /* 150 * If there is a color table, get a pointer to the colors, otherwise return nullptr 151 */ 152 inline const SkPMColor* get_color_ptr(SkColorTable* colorTable) { 153 return nullptr != colorTable ? colorTable->readColors() : nullptr; 154 } 155 156 /* 157 * Given that the encoded image uses a color table, return the fill value 158 */ 159 inline uint32_t get_color_table_fill_value(SkColorType colorType, const SkPMColor* colorPtr, 160 uint8_t fillIndex) { 161 SkASSERT(nullptr != colorPtr); 162 switch (colorType) { 163 case kN32_SkColorType: 164 return colorPtr[fillIndex]; 165 case kRGB_565_SkColorType: 166 return SkPixel32ToPixel16(colorPtr[fillIndex]); 167 case kIndex_8_SkColorType: 168 return fillIndex; 169 default: 170 SkASSERT(false); 171 return 0; 172 } 173 } 174 175 /* 176 * 177 * Copy the codec color table back to the client when kIndex8 color type is requested 178 */ 179 inline void copy_color_table(const SkImageInfo& dstInfo, SkColorTable* colorTable, 180 SkPMColor* inputColorPtr, int* inputColorCount) { 181 if (kIndex_8_SkColorType == dstInfo.colorType()) { 182 SkASSERT(nullptr != inputColorPtr); 183 SkASSERT(nullptr != inputColorCount); 184 SkASSERT(nullptr != colorTable); 185 memcpy(inputColorPtr, colorTable->readColors(), *inputColorCount * sizeof(SkPMColor)); 186 } 187 } 188 189 /* 190 * Compute row bytes for an image using pixels per byte 191 */ 192 inline size_t compute_row_bytes_ppb(int width, uint32_t pixelsPerByte) { 193 return (width + pixelsPerByte - 1) / pixelsPerByte; 194 } 195 196 /* 197 * Compute row bytes for an image using bytes per pixel 198 */ 199 inline size_t compute_row_bytes_bpp(int width, uint32_t bytesPerPixel) { 200 return width * bytesPerPixel; 201 } 202 203 /* 204 * Compute row bytes for an image 205 */ 206 inline size_t compute_row_bytes(int width, uint32_t bitsPerPixel) { 207 if (bitsPerPixel < 16) { 208 SkASSERT(0 == 8 % bitsPerPixel); 209 const uint32_t pixelsPerByte = 8 / bitsPerPixel; 210 return compute_row_bytes_ppb(width, pixelsPerByte); 211 } else { 212 SkASSERT(0 == bitsPerPixel % 8); 213 const uint32_t bytesPerPixel = bitsPerPixel / 8; 214 return compute_row_bytes_bpp(width, bytesPerPixel); 215 } 216 } 217 218 /* 219 * Get a byte from a buffer 220 * This method is unsafe, the caller is responsible for performing a check 221 */ 222 inline uint8_t get_byte(uint8_t* buffer, uint32_t i) { 223 return buffer[i]; 224 } 225 226 /* 227 * Get a short from a buffer 228 * This method is unsafe, the caller is responsible for performing a check 229 */ 230 inline uint16_t get_short(uint8_t* buffer, uint32_t i) { 231 uint16_t result; 232 memcpy(&result, &(buffer[i]), 2); 233 #ifdef SK_CPU_BENDIAN 234 return SkEndianSwap16(result); 235 #else 236 return result; 237 #endif 238 } 239 240 /* 241 * Get an int from a buffer 242 * This method is unsafe, the caller is responsible for performing a check 243 */ 244 inline uint32_t get_int(uint8_t* buffer, uint32_t i) { 245 uint32_t result; 246 memcpy(&result, &(buffer[i]), 4); 247 #ifdef SK_CPU_BENDIAN 248 return SkEndianSwap32(result); 249 #else 250 return result; 251 #endif 252 } 253 254 #endif // SkCodecPriv_DEFINED 255