Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2013 Google Inc.
      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 #include "SkErrorInternals.h"
      9 #include "SkConvolver.h"
     10 #include "SkBitmapProcState.h"
     11 #include "SkBitmap.h"
     12 #include "SkColor.h"
     13 #include "SkColorPriv.h"
     14 #include "SkConvolver.h"
     15 #include "SkUnPreMultiply.h"
     16 #include "SkShader.h"
     17 #include "SkRTConf.h"
     18 #include "SkMath.h"
     19 
     20 // These are the per-scanline callbacks that are used when we must resort to
     21 // resampling an image as it is blitted.  Typically these are used only when
     22 // the image is rotated or has some other complex transformation applied.
     23 // Scaled images will usually be rescaled directly before rasterization.
     24 
     25 namespace {
     26 
     27 template <typename Color, typename ColorPacker>
     28 void highQualityFilter(ColorPacker pack, const SkBitmapProcState& s, int x, int y, Color* SK_RESTRICT colors, int count) {
     29     const int maxX = s.fBitmap->width();
     30     const int maxY = s.fBitmap->height();
     31 
     32     while (count-- > 0) {
     33         SkPoint srcPt;
     34         s.fInvProc(s.fInvMatrix, x + 0.5f,
     35                     y + 0.5f, &srcPt);
     36         srcPt.fX -= SK_ScalarHalf;
     37         srcPt.fY -= SK_ScalarHalf;
     38 
     39         SkScalar weight = 0;
     40         SkScalar fr = 0, fg = 0, fb = 0, fa = 0;
     41 
     42         int y0 = SkClampMax(SkScalarCeilToInt(srcPt.fY-s.getBitmapFilter()->width()), maxY);
     43         int y1 = SkClampMax(SkScalarFloorToInt(srcPt.fY+s.getBitmapFilter()->width()+1), maxY);
     44         int x0 = SkClampMax(SkScalarCeilToInt(srcPt.fX-s.getBitmapFilter()->width()), maxX);
     45         int x1 = SkClampMax(SkScalarFloorToInt(srcPt.fX+s.getBitmapFilter()->width())+1, maxX);
     46 
     47         for (int srcY = y0; srcY < y1; srcY++) {
     48             SkScalar yWeight = s.getBitmapFilter()->lookupScalar((srcPt.fY - srcY));
     49 
     50             for (int srcX = x0; srcX < x1 ; srcX++) {
     51                 SkScalar xWeight = s.getBitmapFilter()->lookupScalar((srcPt.fX - srcX));
     52 
     53                 SkScalar combined_weight = SkScalarMul(xWeight, yWeight);
     54 
     55                 SkPMColor c = *s.fBitmap->getAddr32(srcX, srcY);
     56                 fr += combined_weight * SkGetPackedR32(c);
     57                 fg += combined_weight * SkGetPackedG32(c);
     58                 fb += combined_weight * SkGetPackedB32(c);
     59                 fa += combined_weight * SkGetPackedA32(c);
     60                 weight += combined_weight;
     61             }
     62         }
     63 
     64         fr = SkScalarDiv(fr, weight);
     65         fg = SkScalarDiv(fg, weight);
     66         fb = SkScalarDiv(fb, weight);
     67         fa = SkScalarDiv(fa, weight);
     68 
     69         int a = SkClampMax(SkScalarRoundToInt(fa), 255);
     70         int r = SkClampMax(SkScalarRoundToInt(fr), a);
     71         int g = SkClampMax(SkScalarRoundToInt(fg), a);
     72         int b = SkClampMax(SkScalarRoundToInt(fb), a);
     73 
     74         *colors++ = pack(a, r, g, b);
     75 
     76         x++;
     77     }
     78 }
     79 
     80 uint16_t PackTo565(int /*a*/, int r, int g, int b) {
     81     return SkPack888ToRGB16(r, g, b);
     82 }
     83 
     84 }  // namespace
     85 
     86 void highQualityFilter32(const SkBitmapProcState& s, int x, int y, SkPMColor* SK_RESTRICT colors, int count) {
     87     highQualityFilter(&SkPackARGB32, s, x, y, colors, count);
     88 }
     89 
     90 void highQualityFilter16(const SkBitmapProcState& s, int x, int y, uint16_t* SK_RESTRICT colors, int count) {
     91     highQualityFilter(&PackTo565, s, x, y, colors, count);
     92 }
     93 
     94 
     95 SK_CONF_DECLARE(const char *, c_bitmapFilter, "bitmap.filter", "mitchell", "Which scanline bitmap filter to use [mitchell, lanczos, hamming, gaussian, triangle, box]");
     96 
     97 SkBitmapFilter *SkBitmapFilter::Allocate() {
     98     if (!strcmp(c_bitmapFilter, "mitchell")) {
     99         return SkNEW_ARGS(SkMitchellFilter,(1.f/3.f,1.f/3.f));
    100     } else if (!strcmp(c_bitmapFilter, "lanczos")) {
    101         return SkNEW(SkLanczosFilter);
    102     } else if (!strcmp(c_bitmapFilter, "hamming")) {
    103         return SkNEW(SkHammingFilter);
    104     } else if (!strcmp(c_bitmapFilter, "gaussian")) {
    105         return SkNEW_ARGS(SkGaussianFilter,(2));
    106     } else if (!strcmp(c_bitmapFilter, "triangle")) {
    107         return SkNEW(SkTriangleFilter);
    108     } else if (!strcmp(c_bitmapFilter, "box")) {
    109         return SkNEW(SkBoxFilter);
    110     } else {
    111         SkDEBUGFAIL("Unknown filter type");
    112     }
    113 
    114     return NULL;
    115 }
    116 
    117 bool SkBitmapProcState::setBitmapFilterProcs() {
    118     if (fFilterLevel != SkPaint::kHigh_FilterLevel) {
    119         return false;
    120     }
    121 
    122     if (fAlphaScale != 256) {
    123         return false;
    124     }
    125 
    126     // TODO: consider supporting other colortypes (e.g. 565, A8)
    127     if (fBitmap->colorType() != kN32_SkColorType) {
    128         return false;
    129     }
    130 
    131     // TODO: consider supporting repeat and mirror
    132     if (SkShader::kClamp_TileMode != fTileModeX || SkShader::kClamp_TileMode != fTileModeY) {
    133         return false;
    134     }
    135 
    136     // TODO: is this right?  do we want fBitmapFilter allocated even if we can't set shader procs?
    137     if (fInvType & (SkMatrix::kAffine_Mask | SkMatrix::kScale_Mask)) {
    138         fBitmapFilter = SkBitmapFilter::Allocate();
    139     }
    140 
    141     if (fInvType & SkMatrix::kScale_Mask) {
    142         fShaderProc32 = highQualityFilter32;
    143         fShaderProc16 = highQualityFilter16;
    144         return true;
    145     } else {
    146         return false;
    147     }
    148 }
    149