blob: 2b22922b0c9b158c148b3c0271a0913ccaa2f3bc [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
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()) {
scroggocc2feb12015-08-14 08:32:46 -0700125 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:
msarettb30d6982016-02-15 10:18:45 -0800138 return kOpaque_SkAlphaType == dst.alphaType();
139 case kGray_8_SkColorType:
140 if (kOpaque_SkAlphaType != dst.alphaType()) {
141 return false;
142 }
143 // Fall through
scroggocc2feb12015-08-14 08:32:46 -0700144 default:
145 return dst.colorType() == src.colorType();
146 }
147}
148
149/*
halcanary96fcdcc2015-08-27 07:41:13 -0700150 * If there is a color table, get a pointer to the colors, otherwise return nullptr
msarett99f567e2015-08-05 12:58:26 -0700151 */
msarette6dd0042015-10-09 11:07:34 -0700152inline const SkPMColor* get_color_ptr(SkColorTable* colorTable) {
halcanary96fcdcc2015-08-27 07:41:13 -0700153 return nullptr != colorTable ? colorTable->readColors() : nullptr;
msarett99f567e2015-08-05 12:58:26 -0700154}
155
156/*
msarette6dd0042015-10-09 11:07:34 -0700157 * Given that the encoded image uses a color table, return the fill value
158 */
159inline 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/*
msarett74114382015-03-16 11:55:18 -0700176 *
msarett9e43cab2015-04-29 07:38:43 -0700177 * Copy the codec color table back to the client when kIndex8 color type is requested
msarett9e43cab2015-04-29 07:38:43 -0700178 */
msarette6dd0042015-10-09 11:07:34 -0700179inline void copy_color_table(const SkImageInfo& dstInfo, SkColorTable* colorTable,
msarett9e43cab2015-04-29 07:38:43 -0700180 SkPMColor* inputColorPtr, int* inputColorCount) {
181 if (kIndex_8_SkColorType == dstInfo.colorType()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700182 SkASSERT(nullptr != inputColorPtr);
183 SkASSERT(nullptr != inputColorCount);
184 SkASSERT(nullptr != colorTable);
msarett10522ff2015-09-07 08:54:01 -0700185 memcpy(inputColorPtr, colorTable->readColors(), *inputColorCount * sizeof(SkPMColor));
msarett9e43cab2015-04-29 07:38:43 -0700186 }
187}
188
189/*
msarett74114382015-03-16 11:55:18 -0700190 * Compute row bytes for an image using pixels per byte
msarett74114382015-03-16 11:55:18 -0700191 */
msarette6dd0042015-10-09 11:07:34 -0700192inline size_t compute_row_bytes_ppb(int width, uint32_t pixelsPerByte) {
msarett74114382015-03-16 11:55:18 -0700193 return (width + pixelsPerByte - 1) / pixelsPerByte;
194}
195
196/*
msarett74114382015-03-16 11:55:18 -0700197 * Compute row bytes for an image using bytes per pixel
msarett74114382015-03-16 11:55:18 -0700198 */
msarette6dd0042015-10-09 11:07:34 -0700199inline size_t compute_row_bytes_bpp(int width, uint32_t bytesPerPixel) {
msarett74114382015-03-16 11:55:18 -0700200 return width * bytesPerPixel;
201}
202
203/*
msarett74114382015-03-16 11:55:18 -0700204 * Compute row bytes for an image
msarett74114382015-03-16 11:55:18 -0700205 */
msarette6dd0042015-10-09 11:07:34 -0700206inline size_t compute_row_bytes(int width, uint32_t bitsPerPixel) {
msarett74114382015-03-16 11:55:18 -0700207 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/*
msarett74114382015-03-16 11:55:18 -0700219 * Get a byte from a buffer
220 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700221 */
msarette6dd0042015-10-09 11:07:34 -0700222inline uint8_t get_byte(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700223 return buffer[i];
224}
225
226/*
msarett74114382015-03-16 11:55:18 -0700227 * Get a short from a buffer
228 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700229 */
msarette6dd0042015-10-09 11:07:34 -0700230inline uint16_t get_short(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700231 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/*
msarett74114382015-03-16 11:55:18 -0700241 * Get an int from a buffer
242 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700243 */
msarette6dd0042015-10-09 11:07:34 -0700244inline uint32_t get_int(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700245 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
msarett0e6274f2016-03-21 08:04:40 -0700254/*
255 * @param data Buffer to read bytes from
256 * @param isLittleEndian Output parameter
257 * Indicates if the data is little endian
258 * Is unaffected on false returns
259 */
260inline bool is_valid_endian_marker(const uint8_t* data, bool* isLittleEndian) {
261 // II indicates Intel (little endian) and MM indicates motorola (big endian).
262 if (('I' != data[0] || 'I' != data[1]) && ('M' != data[0] || 'M' != data[1])) {
263 return false;
264 }
265
266 *isLittleEndian = ('I' == data[0]);
267 return true;
268}
269
270inline uint16_t get_endian_short(const uint8_t* data, bool littleEndian) {
271 if (littleEndian) {
272 return (data[1] << 8) | (data[0]);
273 }
274
275 return (data[0] << 8) | (data[1]);
276}
277
msarett74114382015-03-16 11:55:18 -0700278#endif // SkCodecPriv_DEFINED