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.
get_scale_from_sample_size(int sampleSize)23 inline float get_scale_from_sample_size(int sampleSize) {
24 return 1.0f / ((float) sampleSize);
25 }
26
is_valid_subset(const SkIRect & subset,const SkISize & imageDims)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 */
get_scaled_dimension(int srcDimension,int sampleSize)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 */
get_start_coord(int sampleFactor)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 */
get_dst_coord(int srcCoord,int sampleFactor)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 */
is_coord_necessary(int srcCoord,int sampleFactor,int scaledDim)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
valid_alpha(SkAlphaType dstAlpha,SkAlphaType srcAlpha)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 */
conversion_possible(const SkImageInfo & dst,const SkImageInfo & src)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 */
get_color_ptr(SkColorTable * colorTable)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 */
get_color_table_fill_value(SkColorType colorType,const SkPMColor * colorPtr,uint8_t fillIndex)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 */
copy_color_table(const SkImageInfo & dstInfo,SkColorTable * colorTable,SkPMColor * inputColorPtr,int * inputColorCount)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 */
compute_row_bytes_ppb(int width,uint32_t pixelsPerByte)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 */
compute_row_bytes_bpp(int width,uint32_t bytesPerPixel)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 */
compute_row_bytes(int width,uint32_t bitsPerPixel)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 */
get_byte(uint8_t * buffer,uint32_t i)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 */
get_short(uint8_t * buffer,uint32_t i)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 */
get_int(uint8_t * buffer,uint32_t i)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