1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.gallery3d.filtershow.filters; 18 19 import android.graphics.Bitmap; 20 import android.graphics.BitmapFactory; 21 import android.graphics.Canvas; 22 import android.graphics.Color; 23 import android.graphics.Matrix; 24 import android.graphics.Paint; 25 import android.graphics.Paint.Style; 26 import android.graphics.Path; 27 import android.graphics.PathMeasure; 28 import android.graphics.PorterDuff; 29 import android.graphics.PorterDuffColorFilter; 30 31 import com.android.gallery3d.R; 32 import com.android.gallery3d.filtershow.filters.FilterDrawRepresentation.StrokeData; 33 import com.android.gallery3d.filtershow.imageshow.MasterImage; 34 import com.android.gallery3d.filtershow.presets.ImagePreset; 35 36 import java.util.Vector; 37 38 public class ImageFilterDraw extends ImageFilter { 39 private static final String LOGTAG = "ImageFilterDraw"; 40 public final static byte SIMPLE_STYLE = 0; 41 public final static byte BRUSH_STYLE_SPATTER = 1; 42 public final static byte BRUSH_STYLE_MARKER = 2; 43 public final static int NUMBER_OF_STYLES = 3; 44 Bitmap mOverlayBitmap; // this accelerates interaction 45 int mCachedStrokes = -1; 46 int mCurrentStyle = 0; 47 48 FilterDrawRepresentation mParameters = new FilterDrawRepresentation(); 49 ImageFilterDraw()50 public ImageFilterDraw() { 51 mName = "Image Draw"; 52 } 53 54 DrawStyle[] mDrawingsTypes = new DrawStyle[] { 55 new SimpleDraw(), 56 new Brush(R.drawable.brush_marker), 57 new Brush(R.drawable.brush_spatter) 58 }; 59 { 60 for (int i = 0; i < mDrawingsTypes.length; i++) { 61 mDrawingsTypes[i].setType((byte) i); 62 } 63 64 } 65 66 @Override getDefaultRepresentation()67 public FilterRepresentation getDefaultRepresentation() { 68 return new FilterDrawRepresentation(); 69 } 70 71 @Override useRepresentation(FilterRepresentation representation)72 public void useRepresentation(FilterRepresentation representation) { 73 FilterDrawRepresentation parameters = (FilterDrawRepresentation) representation; 74 mParameters = parameters; 75 } 76 setStyle(byte style)77 public void setStyle(byte style) { 78 mCurrentStyle = style % mDrawingsTypes.length; 79 } 80 getStyle()81 public int getStyle() { 82 return mCurrentStyle; 83 } 84 85 public static interface DrawStyle { setType(byte type)86 public void setType(byte type); paint(FilterDrawRepresentation.StrokeData sd, Canvas canvas, Matrix toScrMatrix, int quality)87 public void paint(FilterDrawRepresentation.StrokeData sd, Canvas canvas, Matrix toScrMatrix, 88 int quality); 89 } 90 91 class SimpleDraw implements DrawStyle { 92 byte mType; 93 94 @Override setType(byte type)95 public void setType(byte type) { 96 mType = type; 97 } 98 99 @Override paint(FilterDrawRepresentation.StrokeData sd, Canvas canvas, Matrix toScrMatrix, int quality)100 public void paint(FilterDrawRepresentation.StrokeData sd, Canvas canvas, Matrix toScrMatrix, 101 int quality) { 102 if (sd == null) { 103 return; 104 } 105 if (sd.mPath == null) { 106 return; 107 } 108 Paint paint = new Paint(); 109 110 paint.setStyle(Style.STROKE); 111 paint.setColor(sd.mColor); 112 paint.setStrokeWidth(toScrMatrix.mapRadius(sd.mRadius)); 113 114 // done this way because of a bug in path.transform(matrix) 115 Path mCacheTransPath = new Path(); 116 mCacheTransPath.addPath(sd.mPath, toScrMatrix); 117 118 canvas.drawPath(mCacheTransPath, paint); 119 } 120 } 121 122 class Brush implements DrawStyle { 123 int mBrushID; 124 Bitmap mBrush; 125 byte mType; 126 Brush(int brushID)127 public Brush(int brushID) { 128 mBrushID = brushID; 129 } getBrush()130 public Bitmap getBrush() { 131 if (mBrush == null) { 132 BitmapFactory.Options opt = new BitmapFactory.Options(); 133 opt.inPreferredConfig = Bitmap.Config.ALPHA_8; 134 mBrush = MasterImage.getImage().getImageLoader().decodeImage(mBrushID, opt); 135 mBrush = mBrush.extractAlpha(); 136 } 137 return mBrush; 138 } 139 140 @Override paint(FilterDrawRepresentation.StrokeData sd, Canvas canvas, Matrix toScrMatrix, int quality)141 public void paint(FilterDrawRepresentation.StrokeData sd, Canvas canvas, Matrix toScrMatrix, 142 int quality) { 143 if (sd == null || sd.mPath == null) { 144 return; 145 } 146 Paint paint = new Paint(); 147 paint.setStyle(Style.STROKE); 148 paint.setAntiAlias(true); 149 Path mCacheTransPath = new Path(); 150 mCacheTransPath.addPath(sd.mPath, toScrMatrix); 151 draw(canvas, paint, sd.mColor, toScrMatrix.mapRadius(sd.mRadius) * 2, 152 mCacheTransPath); 153 } 154 createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)155 public Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) 156 { 157 Matrix m = new Matrix(); 158 m.setScale(dstWidth / (float) src.getWidth(), dstHeight / (float) src.getHeight()); 159 Bitmap result = Bitmap.createBitmap(dstWidth, dstHeight, src.getConfig()); 160 Canvas canvas = new Canvas(result); 161 162 Paint paint = new Paint(); 163 paint.setFilterBitmap(filter); 164 canvas.drawBitmap(src, m, paint); 165 166 return result; 167 168 } draw(Canvas canvas, Paint paint, int color, float size, Path path)169 void draw(Canvas canvas, Paint paint, int color, float size, Path path) { 170 PathMeasure mPathMeasure = new PathMeasure(); 171 float[] mPosition = new float[2]; 172 float[] mTan = new float[2]; 173 174 mPathMeasure.setPath(path, false); 175 176 paint.setAntiAlias(true); 177 paint.setColor(color); 178 179 paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY)); 180 Bitmap brush; 181 // done this way because of a bug in 182 // Bitmap.createScaledBitmap(getBrush(),(int) size,(int) size,true); 183 brush = createScaledBitmap(getBrush(), (int) size, (int) size, true); 184 float len = mPathMeasure.getLength(); 185 float s2 = size / 2; 186 float step = s2 / 8; 187 for (float i = 0; i < len; i += step) { 188 mPathMeasure.getPosTan(i, mPosition, mTan); 189 // canvas.drawCircle(pos[0], pos[1], size, paint); 190 canvas.drawBitmap(brush, mPosition[0] - s2, mPosition[1] - s2, paint); 191 } 192 } 193 194 @Override setType(byte type)195 public void setType(byte type) { 196 mType = type; 197 } 198 } 199 paint(FilterDrawRepresentation.StrokeData sd, Canvas canvas, Matrix toScrMatrix, int quality)200 void paint(FilterDrawRepresentation.StrokeData sd, Canvas canvas, Matrix toScrMatrix, 201 int quality) { 202 mDrawingsTypes[sd.mType].paint(sd, canvas, toScrMatrix, quality); 203 } 204 drawData(Canvas canvas, Matrix originalRotateToScreen, int quality)205 public void drawData(Canvas canvas, Matrix originalRotateToScreen, int quality) { 206 Paint paint = new Paint(); 207 if (quality == ImagePreset.QUALITY_FINAL) { 208 paint.setAntiAlias(true); 209 } 210 paint.setStyle(Style.STROKE); 211 paint.setColor(Color.RED); 212 paint.setStrokeWidth(40); 213 214 if (mParameters.getDrawing().isEmpty() && mParameters.getCurrentDrawing() == null) { 215 return; 216 } 217 if (quality == ImagePreset.QUALITY_FINAL) { 218 for (FilterDrawRepresentation.StrokeData strokeData : mParameters.getDrawing()) { 219 paint(strokeData, canvas, originalRotateToScreen, quality); 220 } 221 return; 222 } 223 224 if (mOverlayBitmap == null || 225 mOverlayBitmap.getWidth() != canvas.getWidth() || 226 mOverlayBitmap.getHeight() != canvas.getHeight() || 227 mParameters.getDrawing().size() < mCachedStrokes) { 228 229 mOverlayBitmap = Bitmap.createBitmap( 230 canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888); 231 mCachedStrokes = 0; 232 } 233 234 if (mCachedStrokes < mParameters.getDrawing().size()) { 235 fillBuffer(originalRotateToScreen); 236 } 237 canvas.drawBitmap(mOverlayBitmap, 0, 0, paint); 238 239 StrokeData stroke = mParameters.getCurrentDrawing(); 240 if (stroke != null) { 241 paint(stroke, canvas, originalRotateToScreen, quality); 242 } 243 } 244 fillBuffer(Matrix originalRotateToScreen)245 public void fillBuffer(Matrix originalRotateToScreen) { 246 Canvas drawCache = new Canvas(mOverlayBitmap); 247 Vector<FilterDrawRepresentation.StrokeData> v = mParameters.getDrawing(); 248 int n = v.size(); 249 250 for (int i = mCachedStrokes; i < n; i++) { 251 paint(v.get(i), drawCache, originalRotateToScreen, ImagePreset.QUALITY_PREVIEW); 252 } 253 mCachedStrokes = n; 254 } 255 draw(Canvas canvas, Matrix originalRotateToScreen)256 public void draw(Canvas canvas, Matrix originalRotateToScreen) { 257 for (FilterDrawRepresentation.StrokeData strokeData : mParameters.getDrawing()) { 258 paint(strokeData, canvas, originalRotateToScreen, ImagePreset.QUALITY_PREVIEW); 259 } 260 mDrawingsTypes[mCurrentStyle].paint( 261 null, canvas, originalRotateToScreen, ImagePreset.QUALITY_PREVIEW); 262 } 263 264 @Override apply(Bitmap bitmap, float scaleFactor, int quality)265 public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { 266 int w = bitmap.getWidth(); 267 int h = bitmap.getHeight(); 268 269 Matrix m = getOriginalToScreenMatrix(w, h); 270 drawData(new Canvas(bitmap), m, quality); 271 return bitmap; 272 } 273 274 } 275