blob: 2769cec1cd4025f15611d4c9e5d53e65cb2eb47b [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
msarett9e43cab2015-04-29 07:38:43 -070011#include "SkColorTable.h"
msarett74114382015-03-16 11:55:18 -070012#include "SkImageInfo.h"
13#include "SkSwizzler.h"
14#include "SkTypes.h"
msarett9e43cab2015-04-29 07:38:43 -070015#include "SkUtils.h"
msarett74114382015-03-16 11:55:18 -070016
17/*
18 *
19 * Helper routine for alpha result codes
20 *
21 */
22#define INIT_RESULT_ALPHA \
23 uint8_t zeroAlpha = 0; \
24 uint8_t maxAlpha = 0xFF;
25
26#define UPDATE_RESULT_ALPHA(alpha) \
27 zeroAlpha |= (alpha); \
28 maxAlpha &= (alpha);
29
30#define COMPUTE_RESULT_ALPHA \
31 SkSwizzler::GetResult(zeroAlpha, maxAlpha);
32
msarett5406d6f2015-08-31 06:55:13 -070033/*
msarett10522ff2015-09-07 08:54:01 -070034 * returns a scaled dimension based on the original dimension and the sampleSize
35 * NOTE: we round down here for scaled dimension to match the behavior of SkImageDecoder
36 */
37static int get_scaled_dimension(int srcDimension, int sampleSize) {
38 if (sampleSize > srcDimension) {
39 return 1;
40 }
41 return srcDimension / sampleSize;
42}
43
44/*
msarett5406d6f2015-08-31 06:55:13 -070045 * Returns the first coordinate that we will keep during a scaled decode.
46 * The output can be interpreted as an x-coordinate or a y-coordinate.
47 *
48 * This does not need to be called and is not called when sampleFactor == 1.
49 */
50static int get_start_coord(int sampleFactor) { return sampleFactor / 2; };
51
52/*
53 * Given a coordinate in the original image, this returns the corresponding
54 * coordinate in the scaled image. This function is meaningless if
55 * IsCoordNecessary returns false.
56 * The output can be interpreted as an x-coordinate or a y-coordinate.
57 *
58 * This does not need to be called and is not called when sampleFactor == 1.
59 */
60static int get_dst_coord(int srcCoord, int sampleFactor) { return srcCoord / sampleFactor; };
61
62/*
63 * When scaling, we will discard certain y-coordinates (rows) and
64 * x-coordinates (columns). This function returns true if we should keep the
65 * coordinate and false otherwise.
66 * The inputs may be x-coordinates or y-coordinates.
67 *
68 * This does not need to be called and is not called when sampleFactor == 1.
69 */
70static bool is_coord_necessary(int srcCoord, int sampleFactor, int scaledDim) {
71 // Get the first coordinate that we want to keep
72 int startCoord = get_start_coord(sampleFactor);
73
74 // Return false on edge cases
75 if (srcCoord < startCoord || get_dst_coord(srcCoord, sampleFactor) >= scaledDim) {
76 return false;
77 }
78
79 // Every sampleFactor rows are necessary
80 return ((srcCoord - startCoord) % sampleFactor) == 0;
81}
82
msarett4ab9d5f2015-08-06 15:34:42 -070083static inline bool valid_alpha(SkAlphaType dstAlpha, SkAlphaType srcAlpha) {
84 // Check for supported alpha types
85 if (srcAlpha != dstAlpha) {
86 if (kOpaque_SkAlphaType == srcAlpha) {
87 // If the source is opaque, we must decode to opaque
88 return false;
89 }
90
91 // The source is not opaque
92 switch (dstAlpha) {
93 case kPremul_SkAlphaType:
94 case kUnpremul_SkAlphaType:
95 // The source is not opaque, so either of these is okay
96 break;
97 default:
98 // We cannot decode a non-opaque image to opaque (or unknown)
99 return false;
100 }
101 }
102 return true;
103}
104
msarett74114382015-03-16 11:55:18 -0700105/*
scroggocc2feb12015-08-14 08:32:46 -0700106 * Most of our codecs support the same conversions:
107 * - profileType must be the same
108 * - opaque only to opaque (and 565 only if opaque)
109 * - premul to unpremul and vice versa
110 * - always support N32
111 * - otherwise match the src color type
112 */
113static bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) {
114 if (dst.profileType() != src.profileType()) {
115 return false;
116 }
117
118 // Ensure the alpha type is valid
119 if (!valid_alpha(dst.alphaType(), src.alphaType())) {
120 return false;
121 }
122
123 // Check for supported color types
124 switch (dst.colorType()) {
125 case kN32_SkColorType:
126 return true;
127 case kRGB_565_SkColorType:
128 return src.alphaType() == kOpaque_SkAlphaType;
129 default:
130 return dst.colorType() == src.colorType();
131 }
132}
133
134/*
halcanary96fcdcc2015-08-27 07:41:13 -0700135 * If there is a color table, get a pointer to the colors, otherwise return nullptr
msarett99f567e2015-08-05 12:58:26 -0700136 */
137static const SkPMColor* get_color_ptr(SkColorTable* colorTable) {
halcanary96fcdcc2015-08-27 07:41:13 -0700138 return nullptr != colorTable ? colorTable->readColors() : nullptr;
msarett99f567e2015-08-05 12:58:26 -0700139}
140
141/*
msarett74114382015-03-16 11:55:18 -0700142 *
msarett9e43cab2015-04-29 07:38:43 -0700143 * Copy the codec color table back to the client when kIndex8 color type is requested
msarett9e43cab2015-04-29 07:38:43 -0700144 */
145static inline void copy_color_table(const SkImageInfo& dstInfo, SkColorTable* colorTable,
146 SkPMColor* inputColorPtr, int* inputColorCount) {
147 if (kIndex_8_SkColorType == dstInfo.colorType()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700148 SkASSERT(nullptr != inputColorPtr);
149 SkASSERT(nullptr != inputColorCount);
150 SkASSERT(nullptr != colorTable);
msarett10522ff2015-09-07 08:54:01 -0700151 memcpy(inputColorPtr, colorTable->readColors(), *inputColorCount * sizeof(SkPMColor));
msarett9e43cab2015-04-29 07:38:43 -0700152 }
153}
154
155/*
msarett74114382015-03-16 11:55:18 -0700156 * Compute row bytes for an image using pixels per byte
msarett74114382015-03-16 11:55:18 -0700157 */
158static inline size_t compute_row_bytes_ppb(int width, uint32_t pixelsPerByte) {
159 return (width + pixelsPerByte - 1) / pixelsPerByte;
160}
161
162/*
msarett74114382015-03-16 11:55:18 -0700163 * Compute row bytes for an image using bytes per pixel
msarett74114382015-03-16 11:55:18 -0700164 */
165static inline size_t compute_row_bytes_bpp(int width, uint32_t bytesPerPixel) {
166 return width * bytesPerPixel;
167}
168
169/*
msarett74114382015-03-16 11:55:18 -0700170 * Compute row bytes for an image
msarett74114382015-03-16 11:55:18 -0700171 */
172static inline size_t compute_row_bytes(int width, uint32_t bitsPerPixel) {
173 if (bitsPerPixel < 16) {
174 SkASSERT(0 == 8 % bitsPerPixel);
175 const uint32_t pixelsPerByte = 8 / bitsPerPixel;
176 return compute_row_bytes_ppb(width, pixelsPerByte);
177 } else {
178 SkASSERT(0 == bitsPerPixel % 8);
179 const uint32_t bytesPerPixel = bitsPerPixel / 8;
180 return compute_row_bytes_bpp(width, bytesPerPixel);
181 }
182}
183
184/*
msarett5406d6f2015-08-31 06:55:13 -0700185 * On incomplete images, get the color to fill with
186 */
187static inline SkPMColor get_fill_color_or_index(SkAlphaType alphaType) {
188 // This condition works properly for all supported output color types.
189 // kIndex8: The low 8-bits of both possible return values is 0, which is
190 // our desired default index.
191 // kGray8: The low 8-bits of both possible return values is 0, which is
192 // black, our desired fill value.
193 // kRGB565: The low 16-bits of both possible return values is 0, which is
194 // black, our desired fill value.
195 // kN32: Return black for opaque images and transparent for non-opaque
196 // images.
197 return kOpaque_SkAlphaType == alphaType ?
198 SK_ColorBLACK : SK_ColorTRANSPARENT;
199}
200
201/*
msarett74114382015-03-16 11:55:18 -0700202 * Get a byte from a buffer
203 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700204 */
205static inline uint8_t get_byte(uint8_t* buffer, uint32_t i) {
206 return buffer[i];
207}
208
209/*
msarett74114382015-03-16 11:55:18 -0700210 * Get a short from a buffer
211 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700212 */
213static inline uint16_t get_short(uint8_t* buffer, uint32_t i) {
214 uint16_t result;
215 memcpy(&result, &(buffer[i]), 2);
216#ifdef SK_CPU_BENDIAN
217 return SkEndianSwap16(result);
218#else
219 return result;
220#endif
221}
222
223/*
msarett74114382015-03-16 11:55:18 -0700224 * Get an int from a buffer
225 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700226 */
227static inline uint32_t get_int(uint8_t* buffer, uint32_t i) {
228 uint32_t result;
229 memcpy(&result, &(buffer[i]), 4);
230#ifdef SK_CPU_BENDIAN
231 return SkEndianSwap32(result);
232#else
233 return result;
234#endif
235}
236
scroggo230d4ac2015-03-26 07:15:55 -0700237#ifdef SK_PRINT_CODEC_MESSAGES
238 #define SkCodecPrintf SkDebugf
239#else
240 #define SkCodecPrintf(...)
241#endif
242
msarett74114382015-03-16 11:55:18 -0700243#endif // SkCodecPriv_DEFINED