Home | History | Annotate | Download | only in codec
      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.
     23 inline float get_scale_from_sample_size(int sampleSize) {
     24     return 1.0f / ((float) sampleSize);
     25 }
     26 
     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  */
     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  */
     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  */
     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  */
     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 
     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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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