• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "include/codec/SkCodec.h"
12 #include "include/codec/SkEncodedOrigin.h"
13 #include "include/core/SkImageInfo.h"
14 #include "include/core/SkTypes.h"
15 #include "include/private/SkEncodedInfo.h"
16 #include "src/codec/SkColorPalette.h"
17 #include "src/core/SkColorData.h"
18 
19 #include <string_view>
20 
21 #ifdef SK_PRINT_CODEC_MESSAGES
22     #define SkCodecPrintf SkDebugf
23 #else
24     #define SkCodecPrintf(...)
25 #endif
26 
27 namespace SkCodecs {
28 bool HasDecoder(std::string_view id);
29 }
30 
31 class SkCodecPriv final {
32 public:
GetEncodedInfo(const SkCodec * codec)33     static const SkEncodedInfo& GetEncodedInfo(const SkCodec* codec) {
34         SkASSERT(codec);
35         return codec->getEncodedInfo();
36     }
37 
38     static bool SelectXformFormat(SkColorType colorType,
39                                   bool forColorTable,
40                                   skcms_PixelFormat* outFormat);
41 
42     // FIXME: Consider sharing with dm, nanbench, and tools.
GetScaleFromSampleSize(int sampleSize)43     static float GetScaleFromSampleSize(int sampleSize) { return 1.0f / ((float)sampleSize); }
44 
IsValidSubset(const SkIRect & subset,const SkISize & imageDims)45     static bool IsValidSubset(const SkIRect& subset, const SkISize& imageDims) {
46         return SkIRect::MakeSize(imageDims).contains(subset);
47     }
48 
49     /*
50      * returns a scaled dimension based on the original dimension and the sampleSize
51      * NOTE: we round down here for scaled dimension to match the behavior of SkImageDecoder
52      */
GetSampledDimension(int srcDimension,int sampleSize)53     static int GetSampledDimension(int srcDimension, int sampleSize) {
54         if (sampleSize > srcDimension) {
55             return 1;
56         }
57         return srcDimension / sampleSize;
58     }
59 
60     /*
61      * Returns the first coordinate that we will keep during a scaled decode.
62      * The output can be interpreted as an x-coordinate or a y-coordinate.
63      *
64      * This does not need to be called and is not called when sampleFactor == 1.
65      */
GetStartCoord(int sampleFactor)66     static int GetStartCoord(int sampleFactor) { return sampleFactor / 2; }
67 
68     /*
69      * Given a coordinate in the original image, this returns the corresponding
70      * coordinate in the scaled image.  This function is meaningless if
71      * IsCoordNecessary returns false.
72      * The output can be interpreted as an x-coordinate or a y-coordinate.
73      *
74      * This does not need to be called and is not called when sampleFactor == 1.
75      */
GetDstCoord(int srcCoord,int sampleFactor)76     static int GetDstCoord(int srcCoord, int sampleFactor) { return srcCoord / sampleFactor; }
77 
78     /*
79      * When scaling, we will discard certain y-coordinates (rows) and
80      * x-coordinates (columns).  This function returns true if we should keep the
81      * coordinate and false otherwise.
82      * The inputs may be x-coordinates or y-coordinates.
83      *
84      * This does not need to be called and is not called when sampleFactor == 1.
85      */
IsCoordNecessary(int srcCoord,int sampleFactor,int scaledDim)86     static bool IsCoordNecessary(int srcCoord, int sampleFactor, int scaledDim) {
87         // Get the first coordinate that we want to keep
88         int startCoord = GetStartCoord(sampleFactor);
89 
90         // Return false on edge cases
91         if (srcCoord < startCoord || GetDstCoord(srcCoord, sampleFactor) >= scaledDim) {
92             return false;
93         }
94 
95         // Every sampleFactor rows are necessary
96         return ((srcCoord - startCoord) % sampleFactor) == 0;
97     }
98 
ValidAlpha(SkAlphaType dstAlpha,bool srcIsOpaque)99     static bool ValidAlpha(SkAlphaType dstAlpha, bool srcIsOpaque) {
100         if (kUnknown_SkAlphaType == dstAlpha) {
101             return false;
102         }
103 
104         if (srcIsOpaque) {
105             if (kOpaque_SkAlphaType != dstAlpha) {
106                 SkCodecPrintf(
107                         "Warning: an opaque image should be decoded as opaque "
108                         "- it is being decoded as non-opaque, which will draw slower\n");
109             }
110             return true;
111         }
112 
113         return dstAlpha != kOpaque_SkAlphaType;
114     }
115 
116     /*
117      * If there is a color table, get a pointer to the colors, otherwise return nullptr
118      */
GetColorPtr(SkColorPalette * colorTable)119     static const SkPMColor* GetColorPtr(SkColorPalette* colorTable) {
120         return nullptr != colorTable ? colorTable->readColors() : nullptr;
121     }
122 
123     /*
124      * Compute row bytes for an image using pixels per byte
125      */
ComputeRowBytesPixelsPerByte(int width,uint32_t pixelsPerByte)126     static size_t ComputeRowBytesPixelsPerByte(int width, uint32_t pixelsPerByte) {
127         return (width + pixelsPerByte - 1) / pixelsPerByte;
128     }
129 
130     /*
131      * Compute row bytes for an image using bytes per pixel
132      */
ComputeRowBytesBytesPerPixel(int width,uint32_t bytesPerPixel)133     static size_t ComputeRowBytesBytesPerPixel(int width, uint32_t bytesPerPixel) {
134         return width * bytesPerPixel;
135     }
136 
137     /*
138      * Compute row bytes for an image
139      */
ComputeRowBytes(int width,uint32_t bitsPerPixel)140     static size_t ComputeRowBytes(int width, uint32_t bitsPerPixel) {
141         if (bitsPerPixel < 16) {
142             SkASSERT(0 == 8 % bitsPerPixel);
143             const uint32_t pixelsPerByte = 8 / bitsPerPixel;
144             return ComputeRowBytesPixelsPerByte(width, pixelsPerByte);
145         } else {
146             SkASSERT(0 == bitsPerPixel % 8);
147             const uint32_t bytesPerPixel = bitsPerPixel / 8;
148             return ComputeRowBytesBytesPerPixel(width, bytesPerPixel);
149         }
150     }
151 
152     /*
153      * Get a byte from a buffer
154      * This method is unsafe, the caller is responsible for performing a check
155      */
UnsafeGetByte(const uint8_t * buffer,uint32_t i)156     static uint8_t UnsafeGetByte(const uint8_t* buffer, uint32_t i) { return buffer[i]; }
157 
158     /*
159      * Get a short from a buffer
160      * This method is unsafe, the caller is responsible for performing a check
161      */
UnsafeGetShort(const uint8_t * buffer,uint32_t i)162     static uint16_t UnsafeGetShort(const uint8_t* buffer, uint32_t i) {
163         uint16_t result;
164         memcpy(&result, &(buffer[i]), 2);
165 #ifdef SK_CPU_BENDIAN
166         return SkEndianSwap16(result);
167 #else
168         return result;
169 #endif
170     }
171 
172     /*
173      * Get an int from a buffer
174      * This method is unsafe, the caller is responsible for performing a check
175      */
UnsafeGetInt(const uint8_t * buffer,uint32_t i)176     static uint32_t UnsafeGetInt(const uint8_t* buffer, uint32_t i) {
177         uint32_t result;
178         memcpy(&result, &(buffer[i]), 4);
179 #ifdef SK_CPU_BENDIAN
180         return SkEndianSwap32(result);
181 #else
182         return result;
183 #endif
184     }
185 
186     /*
187      * @param data           Buffer to read bytes from
188      * @param isLittleEndian Output parameter
189      *                       Indicates if the data is little endian
190      *                       Is unaffected on false returns
191      */
IsValidEndianMarker(const uint8_t * data,bool * isLittleEndian)192     static bool IsValidEndianMarker(const uint8_t* data, bool* isLittleEndian) {
193         // II indicates Intel (little endian) and MM indicates motorola (big endian).
194         if (('I' != data[0] || 'I' != data[1]) && ('M' != data[0] || 'M' != data[1])) {
195             return false;
196         }
197 
198         *isLittleEndian = ('I' == data[0]);
199         return true;
200     }
201 
GetEndianShort(const uint8_t * data,bool littleEndian)202     static uint16_t GetEndianShort(const uint8_t* data, bool littleEndian) {
203         if (littleEndian) {
204             return (data[1] << 8) | (data[0]);
205         }
206 
207         return (data[0] << 8) | (data[1]);
208     }
209 
GetEndianInt(const uint8_t * data,bool littleEndian)210     static uint32_t GetEndianInt(const uint8_t* data, bool littleEndian) {
211         if (littleEndian) {
212             return (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | (data[0]);
213         }
214 
215         return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3]);
216     }
217 
PremultiplyARGBasRGBA(U8CPU a,U8CPU r,U8CPU g,U8CPU b)218     static SkPMColor PremultiplyARGBasRGBA(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
219         if (a != 255) {
220             r = SkMulDiv255Round(r, a);
221             g = SkMulDiv255Round(g, a);
222             b = SkMulDiv255Round(b, a);
223         }
224 
225         return SkPackARGB_as_RGBA(a, r, g, b);
226     }
227 
PremultiplyARGBasBGRA(U8CPU a,U8CPU r,U8CPU g,U8CPU b)228     static SkPMColor PremultiplyARGBasBGRA(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
229         if (a != 255) {
230             r = SkMulDiv255Round(r, a);
231             g = SkMulDiv255Round(g, a);
232             b = SkMulDiv255Round(b, a);
233         }
234 
235         return SkPackARGB_as_BGRA(a, r, g, b);
236     }
237 
IsRGBA(SkColorType colorType)238     static bool IsRGBA(SkColorType colorType) {
239 #ifdef SK_PMCOLOR_IS_RGBA
240         return (kBGRA_8888_SkColorType != colorType);
241 #else
242         return (kRGBA_8888_SkColorType == colorType);
243 #endif
244     }
245 
246     // Method for coverting to a 32 bit pixel.
247     using PackColorProc = uint32_t (*)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
248 
ChoosePackColorProc(bool isPremul,SkColorType colorType)249     static PackColorProc ChoosePackColorProc(bool isPremul, SkColorType colorType) {
250         bool isRGBA = IsRGBA(colorType);
251         if (isPremul) {
252             if (isRGBA) {
253                 return &PremultiplyARGBasRGBA;
254             } else {
255                 return &PremultiplyARGBasBGRA;
256             }
257         } else {
258             if (isRGBA) {
259                 return &SkPackARGB_as_RGBA;
260             } else {
261                 return &SkPackARGB_as_BGRA;
262             }
263         }
264     }
265 };
266 
267 #endif // SkCodecPriv_DEFINED
268