blob: 1694784785c8f4f32050c643275369e53ad4d4c6 [file] [log] [blame]
msarett74114382015-03-16 11:55:18 -07001/*
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
msarette6dd0042015-10-09 11:07:34 -070011#include "SkColorPriv.h"
msarett9e43cab2015-04-29 07:38:43 -070012#include "SkColorTable.h"
msarett74114382015-03-16 11:55:18 -070013#include "SkImageInfo.h"
msarett74114382015-03-16 11:55:18 -070014#include "SkTypes.h"
15
scroggoc5560be2016-02-03 09:42:42 -080016#ifdef SK_PRINT_CODEC_MESSAGES
17 #define SkCodecPrintf SkDebugf
18#else
19 #define SkCodecPrintf(...)
20#endif
21
msarett3d9d7a72015-10-21 10:27:10 -070022// FIXME: Consider sharing with dm, nanbench, and tools.
23inline float get_scale_from_sample_size(int sampleSize) {
24 return 1.0f / ((float) sampleSize);
25}
26
27inline bool is_valid_subset(const SkIRect& subset, const SkISize& imageDims) {
28 return SkIRect::MakeSize(imageDims).contains(subset);
29}
30
msarett5406d6f2015-08-31 06:55:13 -070031/*
msarett10522ff2015-09-07 08:54:01 -070032 * 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
msarett3d9d7a72015-10-21 10:27:10 -070034 * FIXME: I think we should call this get_sampled_dimension().
msarett10522ff2015-09-07 08:54:01 -070035 */
msarette6dd0042015-10-09 11:07:34 -070036inline int get_scaled_dimension(int srcDimension, int sampleSize) {
msarett10522ff2015-09-07 08:54:01 -070037 if (sampleSize > srcDimension) {
38 return 1;
39 }
40 return srcDimension / sampleSize;
41}
42
43/*
msarett5406d6f2015-08-31 06:55:13 -070044 * 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 */
msarette6dd0042015-10-09 11:07:34 -070049inline int get_start_coord(int sampleFactor) { return sampleFactor / 2; };
msarett5406d6f2015-08-31 06:55:13 -070050
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 */
msarette6dd0042015-10-09 11:07:34 -070059inline int get_dst_coord(int srcCoord, int sampleFactor) { return srcCoord / sampleFactor; };
msarett5406d6f2015-08-31 06:55:13 -070060
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 */
msarette6dd0042015-10-09 11:07:34 -070069inline bool is_coord_necessary(int srcCoord, int sampleFactor, int scaledDim) {
msarett5406d6f2015-08-31 06:55:13 -070070 // 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
msarette6dd0042015-10-09 11:07:34 -070082inline bool valid_alpha(SkAlphaType dstAlpha, SkAlphaType srcAlpha) {
scroggoc5560be2016-02-03 09:42:42 -080083 if (kUnknown_SkAlphaType == dstAlpha) {
84 return false;
85 }
86
msarett4ab9d5f2015-08-06 15:34:42 -070087 if (srcAlpha != dstAlpha) {
88 if (kOpaque_SkAlphaType == srcAlpha) {
scroggoc5560be2016-02-03 09:42:42 -080089 // 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;
msarett4ab9d5f2015-08-06 15:34:42 -070093 }
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
msarett74114382015-03-16 11:55:18 -0700109/*
scroggocc2feb12015-08-14 08:32:46 -0700110 * Most of our codecs support the same conversions:
111 * - profileType must be the same
scroggoc5560be2016-02-03 09:42:42 -0800112 * - opaque to any alpha type
113 * - 565 only if opaque
scroggocc2feb12015-08-14 08:32:46 -0700114 * - premul to unpremul and vice versa
115 * - always support N32
116 * - otherwise match the src color type
117 */
msarette6dd0042015-10-09 11:07:34 -0700118inline bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) {
msaretta87d6de2016-02-04 15:37:58 -0800119 // FIXME: skbug.com/4895
msarett3ec5db42016-03-23 06:50:59 -0700120 // Currently, we ignore the SkColorProfileType on the SkImageInfo. We
121 // will treat the encoded data as linear regardless of what the client
122 // requests.
scroggocc2feb12015-08-14 08:32:46 -0700123
124 // Ensure the alpha type is valid
125 if (!valid_alpha(dst.alphaType(), src.alphaType())) {
126 return false;
127 }
128
129 // Check for supported color types
130 switch (dst.colorType()) {
msarett34e0ec42016-04-22 16:27:24 -0700131 case kRGBA_8888_SkColorType:
132 case kBGRA_8888_SkColorType:
scroggocc2feb12015-08-14 08:32:46 -0700133 return true;
134 case kRGB_565_SkColorType:
msarettb30d6982016-02-15 10:18:45 -0800135 return kOpaque_SkAlphaType == dst.alphaType();
136 case kGray_8_SkColorType:
137 if (kOpaque_SkAlphaType != dst.alphaType()) {
138 return false;
139 }
140 // Fall through
scroggocc2feb12015-08-14 08:32:46 -0700141 default:
142 return dst.colorType() == src.colorType();
143 }
144}
145
146/*
halcanary96fcdcc2015-08-27 07:41:13 -0700147 * If there is a color table, get a pointer to the colors, otherwise return nullptr
msarett99f567e2015-08-05 12:58:26 -0700148 */
msarette6dd0042015-10-09 11:07:34 -0700149inline const SkPMColor* get_color_ptr(SkColorTable* colorTable) {
halcanary96fcdcc2015-08-27 07:41:13 -0700150 return nullptr != colorTable ? colorTable->readColors() : nullptr;
msarett99f567e2015-08-05 12:58:26 -0700151}
152
153/*
msarette6dd0042015-10-09 11:07:34 -0700154 * Given that the encoded image uses a color table, return the fill value
155 */
156inline uint32_t get_color_table_fill_value(SkColorType colorType, const SkPMColor* colorPtr,
157 uint8_t fillIndex) {
158 SkASSERT(nullptr != colorPtr);
159 switch (colorType) {
msarett34e0ec42016-04-22 16:27:24 -0700160 case kRGBA_8888_SkColorType:
161 case kBGRA_8888_SkColorType:
msarette6dd0042015-10-09 11:07:34 -0700162 return colorPtr[fillIndex];
163 case kRGB_565_SkColorType:
164 return SkPixel32ToPixel16(colorPtr[fillIndex]);
165 case kIndex_8_SkColorType:
166 return fillIndex;
167 default:
168 SkASSERT(false);
169 return 0;
170 }
171}
172
173/*
msarett74114382015-03-16 11:55:18 -0700174 *
msarett9e43cab2015-04-29 07:38:43 -0700175 * Copy the codec color table back to the client when kIndex8 color type is requested
msarett9e43cab2015-04-29 07:38:43 -0700176 */
msarette6dd0042015-10-09 11:07:34 -0700177inline void copy_color_table(const SkImageInfo& dstInfo, SkColorTable* colorTable,
msarett9e43cab2015-04-29 07:38:43 -0700178 SkPMColor* inputColorPtr, int* inputColorCount) {
179 if (kIndex_8_SkColorType == dstInfo.colorType()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700180 SkASSERT(nullptr != inputColorPtr);
181 SkASSERT(nullptr != inputColorCount);
182 SkASSERT(nullptr != colorTable);
msarett10522ff2015-09-07 08:54:01 -0700183 memcpy(inputColorPtr, colorTable->readColors(), *inputColorCount * sizeof(SkPMColor));
msarett9e43cab2015-04-29 07:38:43 -0700184 }
185}
186
187/*
msarett74114382015-03-16 11:55:18 -0700188 * Compute row bytes for an image using pixels per byte
msarett74114382015-03-16 11:55:18 -0700189 */
msarette6dd0042015-10-09 11:07:34 -0700190inline size_t compute_row_bytes_ppb(int width, uint32_t pixelsPerByte) {
msarett74114382015-03-16 11:55:18 -0700191 return (width + pixelsPerByte - 1) / pixelsPerByte;
192}
193
194/*
msarett74114382015-03-16 11:55:18 -0700195 * Compute row bytes for an image using bytes per pixel
msarett74114382015-03-16 11:55:18 -0700196 */
msarette6dd0042015-10-09 11:07:34 -0700197inline size_t compute_row_bytes_bpp(int width, uint32_t bytesPerPixel) {
msarett74114382015-03-16 11:55:18 -0700198 return width * bytesPerPixel;
199}
200
201/*
msarett74114382015-03-16 11:55:18 -0700202 * Compute row bytes for an image
msarett74114382015-03-16 11:55:18 -0700203 */
msarette6dd0042015-10-09 11:07:34 -0700204inline size_t compute_row_bytes(int width, uint32_t bitsPerPixel) {
msarett74114382015-03-16 11:55:18 -0700205 if (bitsPerPixel < 16) {
206 SkASSERT(0 == 8 % bitsPerPixel);
207 const uint32_t pixelsPerByte = 8 / bitsPerPixel;
208 return compute_row_bytes_ppb(width, pixelsPerByte);
209 } else {
210 SkASSERT(0 == bitsPerPixel % 8);
211 const uint32_t bytesPerPixel = bitsPerPixel / 8;
212 return compute_row_bytes_bpp(width, bytesPerPixel);
213 }
214}
215
216/*
msarett74114382015-03-16 11:55:18 -0700217 * Get a byte from a buffer
218 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700219 */
msarette6dd0042015-10-09 11:07:34 -0700220inline uint8_t get_byte(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700221 return buffer[i];
222}
223
224/*
msarett74114382015-03-16 11:55:18 -0700225 * Get a short from a buffer
226 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700227 */
msarette6dd0042015-10-09 11:07:34 -0700228inline uint16_t get_short(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700229 uint16_t result;
230 memcpy(&result, &(buffer[i]), 2);
231#ifdef SK_CPU_BENDIAN
232 return SkEndianSwap16(result);
233#else
234 return result;
235#endif
236}
237
238/*
msarett74114382015-03-16 11:55:18 -0700239 * Get an int from a buffer
240 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700241 */
msarette6dd0042015-10-09 11:07:34 -0700242inline uint32_t get_int(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700243 uint32_t result;
244 memcpy(&result, &(buffer[i]), 4);
245#ifdef SK_CPU_BENDIAN
246 return SkEndianSwap32(result);
247#else
248 return result;
249#endif
250}
251
msarett0e6274f2016-03-21 08:04:40 -0700252/*
253 * @param data Buffer to read bytes from
254 * @param isLittleEndian Output parameter
255 * Indicates if the data is little endian
256 * Is unaffected on false returns
257 */
258inline bool is_valid_endian_marker(const uint8_t* data, bool* isLittleEndian) {
259 // II indicates Intel (little endian) and MM indicates motorola (big endian).
260 if (('I' != data[0] || 'I' != data[1]) && ('M' != data[0] || 'M' != data[1])) {
261 return false;
262 }
263
264 *isLittleEndian = ('I' == data[0]);
265 return true;
266}
267
268inline uint16_t get_endian_short(const uint8_t* data, bool littleEndian) {
269 if (littleEndian) {
270 return (data[1] << 8) | (data[0]);
271 }
272
273 return (data[0] << 8) | (data[1]);
274}
275
msarett34e0ec42016-04-22 16:27:24 -0700276inline SkPMColor premultiply_argb_as_rgba(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
277 if (a != 255) {
278 r = SkMulDiv255Round(r, a);
279 g = SkMulDiv255Round(g, a);
280 b = SkMulDiv255Round(b, a);
281 }
282
283 return SkPackARGB_as_RGBA(a, r, g, b);
284}
285
286inline SkPMColor premultiply_argb_as_bgra(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
287 if (a != 255) {
288 r = SkMulDiv255Round(r, a);
289 g = SkMulDiv255Round(g, a);
290 b = SkMulDiv255Round(b, a);
291 }
292
293 return SkPackARGB_as_BGRA(a, r, g, b);
294}
295
296inline bool is_rgba(SkColorType colorType) {
297#ifdef SK_PMCOLOR_IS_RGBA
298 return (kBGRA_8888_SkColorType != colorType);
299#else
300 return (kRGBA_8888_SkColorType == colorType);
301#endif
302}
303
304// Method for coverting to a 32 bit pixel.
305typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
306
307inline PackColorProc choose_pack_color_proc(bool isPremul, SkColorType colorType) {
308 bool isRGBA = is_rgba(colorType);
309 if (isPremul) {
310 if (isRGBA) {
311 return &premultiply_argb_as_rgba;
312 } else {
313 return &premultiply_argb_as_bgra;
314 }
315 } else {
316 if (isRGBA) {
317 return &SkPackARGB_as_RGBA;
318 } else {
319 return &SkPackARGB_as_BGRA;
320 }
321 }
322}
323
msarett74114382015-03-16 11:55:18 -0700324#endif // SkCodecPriv_DEFINED