/* * Geopaparazzi - Digital field mapping on Android based devices * Copyright (C) 2016 HydroloGIS (www.hydrologis.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package eu.geopaparazzi.library.sketch; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.view.SurfaceHolder; import android.view.SurfaceView; import eu.geopaparazzi.library.database.GPLog; import eu.geopaparazzi.library.sketch.commands.CommandManager; import eu.geopaparazzi.library.sketch.commands.DrawingPath; /** * The drawing surface.. * * <p>Adapted for geopaparazzi.</p> * * @author almondmendoza (http://www.tutorialforandroid.com/) * @author Andrea Antonello (www.hydrologis.com) */ public class DrawingSurface extends SurfaceView implements SurfaceHolder.Callback { private Boolean _run = false; protected DrawThread thread; private Bitmap mBitmap; /** * */ public static boolean isDrawing = true; /** * */ public DrawingPath previewPath; private CommandManager commandManager; private volatile boolean isDisposed = false; /** * @param context the context to use. * @param attrs attributes. */ public DrawingSurface( Context context, AttributeSet attrs ) { super(context, attrs); isDisposed = false; getHolder().addCallback(this); commandManager = new CommandManager(); thread = new DrawThread(getHolder()); } private static Handler previewDoneHandler = new Handler(){ @Override public void handleMessage( Message msg ) { isDrawing = false; } }; private File imageFile; private boolean dumpToImage; class DrawThread extends Thread { private SurfaceHolder mSurfaceHolder; public DrawThread( SurfaceHolder surfaceHolder ) { mSurfaceHolder = surfaceHolder; } public void setRunning( boolean run ) { isDisposed = false; _run = run; } @Override public void run() { Canvas canvas = null; while( _run ) { if (isDrawing == true) { try { canvas = mSurfaceHolder.lockCanvas(null); if (mBitmap == null) { // Logger.i(this, "Canvas not ready yet..."); continue; } if (isDisposed) { break; } final Canvas c = new Canvas(mBitmap); c.drawColor(Color.WHITE); // c.drawColor(0, PorterDuff.Mode.CLEAR); if (canvas == null || mBitmap.isRecycled()) { break; } canvas.drawColor(Color.WHITE); // canvas.drawColor(0, PorterDuff.Mode.CLEAR); commandManager.executeAll(c, previewDoneHandler); // if (Debug.D) { // if (!previewPath.path.isEmpty()) { // Logger.i(this, // "Style: " + previewPath.paint.getStrokeWidth() + "/" + previewPath.paint.getColor()); //$NON-NLS-1$//$NON-NLS-2$ // } // } previewPath.draw(c); canvas.drawBitmap(mBitmap, 0, 0, null); if (dumpToImage) { FileOutputStream out = null; try { out = new FileOutputStream(imageFile); mBitmap.compress(Bitmap.CompressFormat.PNG, 100, out); out.flush(); } catch (Exception e) { GPLog.error(this, null, e); if (out != null) try { out.close(); } catch (IOException e1) { e1.printStackTrace(); } } dumpToImage = false; } } finally { if (canvas != null) { mSurfaceHolder.unlockCanvasAndPost(canvas); } } } } } } /** * @param drawingPath drawing path */ public void addDrawingPath( DrawingPath drawingPath ) { commandManager.addCommand(drawingPath); } /** * @return has more redo. */ public boolean hasMoreRedo() { return commandManager.hasMoreRedo(); } /** * */ public void redo() { isDrawing = true; commandManager.redo(); } /** * */ public void undo() { isDrawing = true; commandManager.undo(); } /** * @return more undo */ public boolean hasMoreUndo() { return commandManager.hasMoreUndo(); } public void surfaceChanged( SurfaceHolder holder, int format, int width, int height ) { mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); if (GPLog.LOG) GPLog.addLogEntry(this, "Recreating bitmap"); } public void surfaceCreated( SurfaceHolder holder ) { if (!_run) { thread.setRunning(true); thread.start(); } } public void surfaceDestroyed( SurfaceHolder holder ) { boolean retry = true; thread.setRunning(false); while( retry ) { try { thread.join(); retry = false; } catch (InterruptedException e) { // we will try it again and again... } } } /** * */ public void dispose() { if (mBitmap != null) { isDisposed = true; mBitmap.recycle(); mBitmap = null; } } /** * Dump image to file. * * @param imageFile the file. * @throws IOException if something goes wrong. */ public void dumpImage( File imageFile ) throws IOException { this.imageFile = imageFile; dumpToImage = true; } }