1 /* 2 * Copyright (C) 2013 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.Color; 20 import android.graphics.Path; 21 import android.graphics.PathMeasure; 22 import android.util.JsonReader; 23 import android.util.JsonWriter; 24 import android.util.Log; 25 26 import com.android.gallery3d.R; 27 import com.android.gallery3d.filtershow.controller.BasicParameterInt; 28 import com.android.gallery3d.filtershow.controller.BasicParameterStyle; 29 import com.android.gallery3d.filtershow.controller.Parameter; 30 import com.android.gallery3d.filtershow.controller.ParameterBrightness; 31 import com.android.gallery3d.filtershow.controller.ParameterColor; 32 import com.android.gallery3d.filtershow.controller.ParameterHue; 33 import com.android.gallery3d.filtershow.controller.ParameterOpacity; 34 import com.android.gallery3d.filtershow.controller.ParameterSaturation; 35 import com.android.gallery3d.filtershow.editors.EditorDraw; 36 37 import java.io.IOException; 38 import java.util.Arrays; 39 import java.util.Iterator; 40 import java.util.Vector; 41 42 public class FilterDrawRepresentation extends FilterRepresentation { 43 private static final String LOGTAG = "FilterDrawRepresentation"; 44 45 public static final int PARAM_SIZE = 0; 46 public static final int PARAM_STYLE = 1; 47 public static final int PARAM_COLOR = 2; 48 private BasicParameterInt mParamSize = new BasicParameterInt(PARAM_SIZE, 30, 2, 300); 49 private BasicParameterStyle mParamStyle = new BasicParameterStyle(PARAM_STYLE, 5); 50 public static int DEFAULT_MENU_COLOR1 = Color.RED & 0x80FFFFFF; 51 public static int DEFAULT_MENU_COLOR2 = Color.GREEN & 0x80FFFFFF; 52 public static int DEFAULT_MENU_COLOR3 = Color.BLUE & 0x80FFFFFF; 53 public static int DEFAULT_MENU_COLOR4 = Color.BLACK & 0x80FFFFFF; 54 public static int DEFAULT_MENU_COLOR5 = Color.WHITE & 0x80FFFFFF; 55 ParameterColor mParamColor = new ParameterColor(PARAM_COLOR,DEFAULT_MENU_COLOR1); 56 int mParamMode; 57 Parameter mCurrentParam = mParamSize; 58 private static final String SERIAL_COLOR = "color"; 59 private static final String SERIAL_RADIUS = "radius"; 60 private static final String SERIAL_TYPE = "type"; 61 private static final String SERIAL_POINTS_COUNT = "point_count"; 62 private static final String SERIAL_POINTS = "points"; 63 private static final String SERIAL_PATH = "path"; 64 65 66 private Parameter[] mAllParam = { 67 mParamSize, 68 mParamStyle, 69 mParamColor 70 }; 71 72 public void setPramMode(int mode) { 73 mParamMode = mode; 74 mCurrentParam = mAllParam[mParamMode]; 75 } 76 77 public int getParamMode() { 78 return mParamMode; 79 } 80 81 public Parameter getCurrentParam() { 82 return mAllParam[mParamMode]; 83 } 84 85 public Parameter getParam(int type) { 86 return mAllParam[type]; 87 } 88 89 public static class StrokeData implements Cloneable { 90 public byte mType; 91 public Path mPath; 92 public float mRadius; 93 public int mColor; 94 public int noPoints = 0; 95 public float[] mPoints = new float[20]; 96 97 public StrokeData() { 98 } 99 100 public StrokeData(StrokeData copy) { 101 mType = copy.mType; 102 mPath = new Path(copy.mPath); 103 mRadius = copy.mRadius; 104 mColor = copy.mColor; 105 noPoints = copy.noPoints; 106 mPoints = Arrays.copyOf(copy.mPoints, copy.mPoints.length); 107 } 108 109 @Override 110 public boolean equals(Object o) { 111 if (!(o instanceof StrokeData)) { 112 return false; 113 } 114 StrokeData sd = (StrokeData) o; 115 if (mType != sd.mType 116 || mRadius != sd.mRadius 117 || noPoints != sd.noPoints 118 || mColor != sd.mColor) { 119 return false; 120 } 121 return mPath.equals(sd.mPath); 122 } 123 124 @Override 125 public String toString() { 126 return "stroke(" + mType + ", path(" + (mPath) + "), " + mRadius + " , " 127 + Integer.toHexString(mColor) + ")"; 128 } 129 130 @Override 131 public StrokeData clone() throws CloneNotSupportedException { 132 return (StrokeData) super.clone(); 133 } 134 } 135 136 static String colorHexString(int val) { 137 String str = "00000000" + Integer.toHexString(val); 138 str = "0x" + str.substring(str.length() - 8); 139 return str; 140 } 141 142 public String getValueString() { 143 int val; 144 switch (mParamMode) { 145 case PARAM_COLOR: 146 val = ((ParameterColor) mAllParam[mParamMode]).getValue(); 147 return ""; 148 case PARAM_SIZE: 149 val = ((BasicParameterInt) mAllParam[mParamMode]).getValue(); 150 return ((val > 0) ? " +" : " ") + val; 151 case PARAM_STYLE: 152 return ""; 153 } 154 return ""; 155 } 156 157 private Vector<StrokeData> mDrawing = new Vector<StrokeData>(); 158 private StrokeData mCurrent; // used in the currently drawing style 159 160 public FilterDrawRepresentation() { 161 super("Draw"); 162 setFilterClass(ImageFilterDraw.class); 163 setSerializationName("DRAW"); 164 setFilterType(FilterRepresentation.TYPE_VIGNETTE); 165 setTextId(R.string.imageDraw); 166 setEditorId(EditorDraw.ID); 167 setOverlayId(R.drawable.filtershow_drawing); 168 setOverlayOnly(true); 169 } 170 171 @Override 172 public String toString() { 173 return getName() + " : strokes=" + mDrawing.size() 174 + ((mCurrent == null) ? " no current " 175 : ("draw=" + mCurrent.mType + " " + mCurrent.noPoints)); 176 } 177 178 public Vector<StrokeData> getDrawing() { 179 return mDrawing; 180 } 181 182 public StrokeData getCurrentDrawing() { 183 return mCurrent; 184 } 185 186 @Override 187 public FilterRepresentation copy() { 188 FilterDrawRepresentation representation = new FilterDrawRepresentation(); 189 copyAllParameters(representation); 190 return representation; 191 } 192 193 @Override 194 protected void copyAllParameters(FilterRepresentation representation) { 195 super.copyAllParameters(representation); 196 representation.useParametersFrom(this); 197 } 198 199 @Override 200 public boolean isNil() { 201 return getDrawing().isEmpty(); 202 } 203 204 @Override 205 public void useParametersFrom(FilterRepresentation a) { 206 if (a instanceof FilterDrawRepresentation) { 207 FilterDrawRepresentation representation = (FilterDrawRepresentation) a; 208 mParamColor.copyPalletFrom(representation.mParamColor); 209 try { 210 if (representation.mCurrent != null) { 211 mCurrent = (StrokeData) representation.mCurrent.clone(); 212 } else { 213 mCurrent = null; 214 } 215 if (representation.mDrawing != null) { 216 mDrawing = new Vector<StrokeData>(); 217 for (Iterator<StrokeData> elem = representation.mDrawing.iterator(); elem.hasNext(); ) { 218 StrokeData next = elem.next(); 219 mDrawing.add(new StrokeData(next)); 220 } 221 } else { 222 mDrawing = null; 223 } 224 225 } catch (CloneNotSupportedException e) { 226 e.printStackTrace(); 227 } 228 } else { 229 Log.v(LOGTAG, "cannot use parameters from " + a); 230 } 231 } 232 233 @Override 234 public boolean equals(FilterRepresentation representation) { 235 if (!super.equals(representation)) { 236 return false; 237 } 238 if (representation instanceof FilterDrawRepresentation) { 239 FilterDrawRepresentation fdRep = (FilterDrawRepresentation) representation; 240 if (fdRep.mDrawing.size() != mDrawing.size()) 241 return false; 242 if (fdRep.mCurrent == null ^ (mCurrent == null || mCurrent.mPath == null)) { 243 return false; 244 } 245 246 247 if (fdRep.mCurrent != null && mCurrent != null && mCurrent.mPath != null) { 248 if (fdRep.mCurrent.noPoints == mCurrent.noPoints) { 249 return true; 250 } 251 return false; 252 } 253 254 int n = mDrawing.size(); 255 for (int i = 0; i < n; i++) { 256 StrokeData a = mDrawing.get(i); 257 StrokeData b = mDrawing.get(i); 258 if (!a.equals(b)){ 259 return false; 260 } 261 } 262 return true; 263 } 264 return false; 265 } 266 267 private int computeCurrentColor(){ 268 return mParamColor.getValue(); 269 } 270 271 public void fillStrokeParameters(StrokeData sd){ 272 byte type = (byte) mParamStyle.getSelected(); 273 int color = computeCurrentColor(); 274 float size = mParamSize.getValue(); 275 sd.mColor = color; 276 sd.mRadius = size; 277 sd.mType = type; 278 } 279 280 public void startNewSection(float x, float y) { 281 mCurrent = new StrokeData(); 282 fillStrokeParameters(mCurrent); 283 mCurrent.mPath = new Path(); 284 mCurrent.mPath.moveTo(x, y); 285 mCurrent.mPoints[0] = x; 286 mCurrent.mPoints[1] = y; 287 mCurrent.noPoints = 1; 288 } 289 290 public void addPoint(float x, float y) { 291 int len = mCurrent.noPoints * 2; 292 mCurrent.mPath.lineTo(x, y); 293 if ((len+2) > mCurrent.mPoints.length) { 294 mCurrent.mPoints = Arrays.copyOf(mCurrent.mPoints, mCurrent.mPoints.length * 2); 295 } 296 mCurrent.mPoints[len] = x; 297 mCurrent.mPoints[len + 1] = y; 298 mCurrent.noPoints++; 299 } 300 301 public void endSection(float x, float y) { 302 addPoint(x, y); 303 mDrawing.add(mCurrent); 304 mCurrent = null; 305 } 306 307 public void clearCurrentSection() { 308 mCurrent = null; 309 } 310 311 public void clear() { 312 mCurrent = null; 313 mDrawing.clear(); 314 } 315 316 @Override 317 public void serializeRepresentation(JsonWriter writer) throws IOException { 318 writer.beginObject(); 319 int len = mDrawing.size(); 320 int count = 0; 321 float[] mPosition = new float[2]; 322 float[] mTan = new float[2]; 323 324 PathMeasure mPathMeasure = new PathMeasure(); 325 for (int i = 0; i < len; i++) { 326 writer.name(SERIAL_PATH + i); 327 writer.beginObject(); 328 StrokeData mark = mDrawing.get(i); 329 writer.name(SERIAL_COLOR).value(mark.mColor); 330 writer.name(SERIAL_RADIUS).value(mark.mRadius); 331 writer.name(SERIAL_TYPE).value(mark.mType); 332 writer.name(SERIAL_POINTS_COUNT).value(mark.noPoints); 333 writer.name(SERIAL_POINTS); 334 335 writer.beginArray(); 336 int npoints = mark.noPoints * 2; 337 for (int j = 0; j < npoints; j++) { 338 writer.value(mark.mPoints[j]); 339 } 340 writer.endArray(); 341 writer.endObject(); 342 } 343 writer.endObject(); 344 } 345 346 @Override 347 public void deSerializeRepresentation(JsonReader sreader) throws IOException { 348 sreader.beginObject(); 349 Vector<StrokeData> strokes = new Vector<StrokeData>(); 350 351 while (sreader.hasNext()) { 352 sreader.nextName(); 353 sreader.beginObject(); 354 StrokeData stroke = new StrokeData(); 355 356 while (sreader.hasNext()) { 357 String name = sreader.nextName(); 358 if (name.equals(SERIAL_COLOR)) { 359 stroke.mColor = sreader.nextInt(); 360 } else if (name.equals(SERIAL_RADIUS)) { 361 stroke.mRadius = (float) sreader.nextDouble(); 362 } else if (name.equals(SERIAL_TYPE)) { 363 stroke.mType = (byte) sreader.nextInt(); 364 } else if (name.equals(SERIAL_POINTS_COUNT)) { 365 stroke.noPoints = sreader.nextInt(); 366 } else if (name.equals(SERIAL_POINTS)) { 367 368 int count = 0; 369 sreader.beginArray(); 370 while (sreader.hasNext()) { 371 if ((count + 1) > stroke.mPoints.length) { 372 stroke.mPoints = Arrays.copyOf(stroke.mPoints, count * 2); 373 } 374 stroke.mPoints[count++] = (float) sreader.nextDouble(); 375 } 376 stroke.mPath = new Path(); 377 stroke.mPath.moveTo(stroke.mPoints[0], stroke.mPoints[1]); 378 for (int i = 0; i < count; i += 2) { 379 stroke.mPath.lineTo(stroke.mPoints[i], stroke.mPoints[i + 1]); 380 } 381 sreader.endArray(); 382 strokes.add(stroke); 383 } else { 384 sreader.skipValue(); 385 } 386 } 387 sreader.endObject(); 388 } 389 390 mDrawing = strokes; 391 392 sreader.endObject(); 393 } 394 } 395