Merge pull request #42 from LonamiWebs/master

Allow saving to svg
This commit is contained in:
Tibor Kaputa 2017-01-20 18:49:40 +01:00 committed by GitHub
commit 6e7b73b681
9 changed files with 258 additions and 80 deletions

View File

@ -94,6 +94,10 @@ public class MyCanvas extends View {
return bitmap; return bitmap;
} }
public Map<MyPath,PaintOptions> getPaths() {
return mPaths;
}
@Override @Override
protected void onDraw(Canvas canvas) { protected void onDraw(Canvas canvas) {
super.onDraw(canvas); super.onDraw(canvas);

View File

@ -2,6 +2,11 @@ package com.simplemobiletools.draw;
import android.graphics.Path; import android.graphics.Path;
import com.simplemobiletools.draw.actions.Action;
import com.simplemobiletools.draw.actions.Line;
import com.simplemobiletools.draw.actions.Move;
import com.simplemobiletools.draw.actions.Quad;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.Serializable; import java.io.Serializable;
@ -45,54 +50,7 @@ class MyPath extends Path implements Serializable {
super.quadTo(x1, y1, x2, y2); super.quadTo(x1, y1, x2, y2);
} }
private interface Action extends Serializable { List<Action> getActions() {
void perform(Path path); return actions;
}
private static final class Move implements Action {
private final float x, y;
Move(float x, float y) {
this.x = x;
this.y = y;
}
@Override
public void perform(Path path) {
path.moveTo(x, y);
}
}
private static final class Line implements Action {
private final float x, y;
Line(float x, float y) {
this.x = x;
this.y = y;
}
@Override
public void perform(Path path) {
path.lineTo(x, y);
}
}
private static final class Quad implements Action {
private final float x1, y1, x2, y2;
private Quad(float x1, float y1, float x2, float y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
@Override
public void perform(Path path) {
path.quadTo(x1, y1, x2, y2);
}
} }
} }

View File

@ -0,0 +1,69 @@
package com.simplemobiletools.draw;
import android.graphics.drawable.ColorDrawable;
import com.simplemobiletools.draw.actions.Action;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Map;
public class Svg {
public static void saveSvg(File output, MyCanvas canvas)
throws Exception {
// This might throw ClassCastException
int backgroundColor = ((ColorDrawable) canvas.getBackground()).getColor();
// This might throw IOException
FileOutputStream out = new FileOutputStream(output);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
writeSvg(writer, backgroundColor, canvas.getPaths(), canvas.getWidth(), canvas.getHeight());
writer.close();
}
private static void writeSvg(Writer writer, int backgroundColor,
Map<MyPath, PaintOptions> paths, int width, int height)
throws IOException {
writer.write("<svg width=\"");
writer.write(String.valueOf(width));
writer.write("\" height=\"");
writer.write(String.valueOf(height));
writer.write("\" xmlns=\"http://www.w3.org/2000/svg\">");
// Background color (use a rect)
writer.write("<rect width=\"");
writer.write(String.valueOf(width));
writer.write("\" height=\"");
writer.write(String.valueOf(height));
writer.write("\" fill=\"#");
writer.write(Integer.toHexString(backgroundColor).substring(2)); // Skip the alpha FF
writer.write("\"/>");
// Write the paths
for (Map.Entry<MyPath, PaintOptions> entry : paths.entrySet()) {
writePath(writer, entry.getKey(), entry.getValue());
}
writer.write("</svg>");
}
private static void writePath(Writer writer, MyPath path, PaintOptions options)
throws IOException {
writer.write("<path d=\"");
for (Action action : path.getActions()) {
action.perform(writer);
writer.write(' ');
}
writer.write("\" fill=\"none\" stroke=\"#");
writer.write(Integer.toHexString(options.color).substring(2)); // Skip the alpha FF
writer.write("\" stroke-width=\"");
writer.write(String.valueOf(options.strokeWidth));
writer.write("\" stroke-linecap=\"round\"/>");
}
}

View File

@ -0,0 +1,12 @@
package com.simplemobiletools.draw.actions;
import android.graphics.Path;
import java.io.IOException;
import java.io.Serializable;
import java.io.Writer;
public interface Action extends Serializable {
void perform(Path path);
void perform(Writer writer) throws IOException;
}

View File

@ -0,0 +1,29 @@
package com.simplemobiletools.draw.actions;
import android.graphics.Path;
import java.io.IOException;
import java.io.Writer;
public final class Line implements Action {
private final float x, y;
public Line(float x, float y) {
this.x = x;
this.y = y;
}
@Override
public void perform(Path path) {
path.lineTo(x, y);
}
@Override
public void perform(Writer writer) throws IOException {
writer.write("L");
writer.write(String.valueOf(x));
writer.write(",");
writer.write(String.valueOf(y));
}
}

View File

@ -0,0 +1,30 @@
package com.simplemobiletools.draw.actions;
import android.graphics.Path;
import java.io.IOException;
import java.io.Writer;
public final class Move implements Action {
private final float x, y;
public Move(float x, float y) {
this.x = x;
this.y = y;
}
@Override
public void perform(Path path) {
path.moveTo(x, y);
}
@Override
public void perform(Writer writer) throws IOException {
writer.write('M');
writer.write(String.valueOf(x));
writer.write(',');
writer.write(String.valueOf(y));
}
}

View File

@ -0,0 +1,35 @@
package com.simplemobiletools.draw.actions;
import android.graphics.Path;
import java.io.IOException;
import java.io.Writer;
public final class Quad implements Action {
private final float x1, y1, x2, y2;
public Quad(float x1, float y1, float x2, float y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
@Override
public void perform(Path path) {
path.quadTo(x1, y1, x2, y2);
}
@Override
public void perform(Writer writer) throws IOException {
writer.write('Q');
writer.write(String.valueOf(x1));
writer.write(',');
writer.write(String.valueOf(y1));
writer.write(' ');
writer.write(String.valueOf(x2));
writer.write(',');
writer.write(String.valueOf(y2));
}
}

View File

@ -19,12 +19,14 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.RadioGroup;
import android.widget.SeekBar; import android.widget.SeekBar;
import android.widget.Toast; import android.widget.Toast;
import com.simplemobiletools.draw.Config; import com.simplemobiletools.draw.Config;
import com.simplemobiletools.draw.MyCanvas; import com.simplemobiletools.draw.MyCanvas;
import com.simplemobiletools.draw.R; import com.simplemobiletools.draw.R;
import com.simplemobiletools.draw.Svg;
import com.simplemobiletools.draw.Utils; import com.simplemobiletools.draw.Utils;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -50,6 +52,7 @@ public class MainActivity extends SimpleActivity implements MyCanvas.PathsChange
@BindView(R.id.stroke_width_bar) SeekBar mStrokeWidthBar; @BindView(R.id.stroke_width_bar) SeekBar mStrokeWidthBar;
private String curFileName; private String curFileName;
private int curExtensionId;
private int color; private int color;
private float strokeWidth; private float strokeWidth;
@ -163,6 +166,11 @@ public class MainActivity extends SimpleActivity implements MyCanvas.PathsChange
final EditText fileNameET = (EditText) saveFileView.findViewById(R.id.file_name); final EditText fileNameET = (EditText) saveFileView.findViewById(R.id.file_name);
fileNameET.setText(curFileName); fileNameET.setText(curFileName);
final RadioGroup fileExtensionRG = (RadioGroup) saveFileView.findViewById(R.id.extension_radio_group);
if (curExtensionId != 0) {
fileExtensionRG.check(curExtensionId);
}
builder.setView(saveFileView); builder.setView(saveFileView);
builder.setPositiveButton(R.string.ok, null); builder.setPositiveButton(R.string.ok, null);
@ -174,10 +182,18 @@ public class MainActivity extends SimpleActivity implements MyCanvas.PathsChange
@Override @Override
public void onClick(View v) { public void onClick(View v) {
final String fileName = fileNameET.getText().toString().trim(); final String fileName = fileNameET.getText().toString().trim();
if (!fileName.isEmpty()) { if (!fileName.isEmpty()) {
if (saveFile(fileName + ".png")) { final String extension;
switch (fileExtensionRG.getCheckedRadioButtonId()) {
default:
case R.id.extension_radio_png: extension = ".png"; break;
case R.id.extension_radio_svg: extension = ".svg"; break;
}
if (saveFile(fileName, extension)) {
curFileName = fileName; curFileName = fileName;
curExtensionId = fileExtensionRG.getCheckedRadioButtonId();
Utils.showToast(getApplicationContext(), R.string.saving_ok); Utils.showToast(getApplicationContext(), R.string.saving_ok);
alertDialog.dismiss(); alertDialog.dismiss();
} else { } else {
@ -190,7 +206,7 @@ public class MainActivity extends SimpleActivity implements MyCanvas.PathsChange
}); });
} }
private boolean saveFile(final String fileName) { private boolean saveFile(final String fileName, final String extension) {
final String path = Environment.getExternalStorageDirectory().toString(); final String path = Environment.getExternalStorageDirectory().toString();
final File directory = new File(path, SAVE_FOLDER_NAME); final File directory = new File(path, SAVE_FOLDER_NAME);
if (!directory.exists()) { if (!directory.exists()) {
@ -199,24 +215,41 @@ public class MainActivity extends SimpleActivity implements MyCanvas.PathsChange
} }
} }
final Bitmap bitmap = mMyCanvas.getBitmap(); final File file = new File(directory, fileName+extension);
FileOutputStream out = null; switch (extension) {
try { case ".png":
final File file = new File(directory, fileName); final Bitmap bitmap = mMyCanvas.getBitmap();
out = new FileOutputStream(file); FileOutputStream out = null;
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); try {
MediaScannerConnection.scanFile(getApplicationContext(), new String[]{file.getAbsolutePath()}, null, null); out = new FileOutputStream(file);
} catch (Exception e) { bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
Log.e(TAG, "MainActivity SaveFile " + e.getMessage()); MediaScannerConnection.scanFile(getApplicationContext(),
return false; new String[]{file.getAbsolutePath()}, null, null);
} finally { } catch (Exception e) {
try { Log.e(TAG, "MainActivity SaveFile (.png) " + e.getMessage());
if (out != null) { return false;
out.close(); } finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
Log.e(TAG, "MainActivity SaveFile (.png) 2 " + e.getMessage());
}
} }
} catch (IOException e) { break;
Log.e(TAG, "MainActivity SaveFile 2 " + e.getMessage());
} case ".svg":
try {
Svg.saveSvg(file, mMyCanvas);
} catch (Exception e) {
Log.e(TAG, "MainActivity SaveFile (.svg) " + e.getMessage());
return false;
}
break;
default:
return false;
} }
return true; return true;

View File

@ -17,18 +17,26 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/file_name_label" android:layout_below="@+id/file_name_label"
android:layout_marginBottom="@dimen/activity_margin" android:layout_marginBottom="@dimen/activity_margin"
android:layout_toLeftOf="@+id/file_extension"
android:singleLine="true"/> android:singleLine="true"/>
<TextView <RadioGroup
android:id="@+id/file_extension" android:id="@+id/extension_radio_group"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:layout_alignBottom="@+id/file_name" android:layout_below="@+id/file_name"
android:layout_alignParentRight="true" android:checkedButton="@+id/extension_radio_png">
android:layout_alignTop="@+id/file_name"
android:layout_below="@+id/file_name_label" <RadioButton
android:gravity="center_vertical" android:id="@+id/extension_radio_png"
android:text=".png"/> android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=".png"/>
<RadioButton
android:id="@+id/extension_radio_svg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=".svg"/>
</RadioGroup>
</RelativeLayout> </RelativeLayout>