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 25namespace { 26 27template <typename Color, typename ColorPacker> 28void 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 80uint16_t PackTo565(int /*a*/, int r, int g, int b) { 81 return SkPack888ToRGB16(r, g, b); 82} 83 84} // namespace 85 86void highQualityFilter32(const SkBitmapProcState& s, int x, int y, SkPMColor* SK_RESTRICT colors, int count) { 87 highQualityFilter(&SkPackARGB32, s, x, y, colors, count); 88} 89 90void 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 95SK_CONF_DECLARE(const char *, c_bitmapFilter, "bitmap.filter", "mitchell", "Which scanline bitmap filter to use [mitchell, lanczos, hamming, gaussian, triangle, box]"); 96 97SkBitmapFilter *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 117bool 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