diff --git a/README.md b/README.md
index b27c400b..98f2e99d 100644
--- a/README.md
+++ b/README.md
@@ -96,9 +96,9 @@ SVGs of up to size 480 x 360 will fit into the view window of the paint editor,
`imageFormat`: 'svg', 'png', or 'jpg'. Other formats are currently not supported.
-`rotationCenterX`: x coordinate relative to the top left corner of the sprite of the point that should be centered.
+`rotationCenterX`: x coordinate relative to the top left corner of the sprite of the point that should be centered. If left undefined, image will be horizontally centered.
-`rotationCenterY`: y coordinate relative to the top left corner of the sprite of the point that should be centered.
+`rotationCenterY`: y coordinate relative to the top left corner of the sprite of the point that should be centered. If left undefined, image will be vertcally centered.
`rtl`: True if the paint editor should be laid out right to left (meant for right to left languages)
diff --git a/src/containers/paper-canvas.jsx b/src/containers/paper-canvas.jsx
index 2b2ce63a..256f864b 100644
--- a/src/containers/paper-canvas.jsx
+++ b/src/containers/paper-canvas.jsx
@@ -148,6 +148,13 @@ class PaperCanvas extends React.Component {
if (!this.queuedImageToLoad) return;
this.queuedImageToLoad = null;
+ if (typeof rotationCenterX === 'undefined') {
+ rotationCenterX = imgElement.width / 2;
+ }
+ if (typeof rotationCenterY === 'undefined') {
+ rotationCenterY = imgElement.height / 2;
+ }
+
getRaster().drawImage(
imgElement,
(ART_BOARD_WIDTH / 2) - rotationCenterX,
diff --git a/src/playground/playground.css b/src/playground/playground.css
index f6144dfe..0b8e3f3d 100644
--- a/src/playground/playground.css
+++ b/src/playground/playground.css
@@ -4,7 +4,7 @@ body {
margin: 0px;
}
-body, html {
+body, html, .wrapper {
height: 100%
}
@@ -12,4 +12,12 @@ body, html {
height: 90%;
width: 90%;
margin: auto;
-}
\ No newline at end of file
+}
+
+#fileInput {
+ display: none;
+}
+
+.playgroundButton {
+ margin: 4px;
+}
diff --git a/src/playground/playground.jsx b/src/playground/playground.jsx
index 8ccc8684..963ed980 100644
--- a/src/playground/playground.jsx
+++ b/src/playground/playground.jsx
@@ -29,50 +29,152 @@ class Playground extends React.Component {
constructor (props) {
super(props);
bindAll(this, [
+ 'downloadImage',
'handleUpdateName',
- 'handleUpdateImage'
+ 'handleUpdateImage',
+ 'onUploadImage'
]);
// Append ?dir=rtl to URL to get RTL layout
const match = location.search.match(/dir=([^&]+)/);
const rtl = match && match[1] == 'rtl';
+ this.id = 0;
this.state = {
name: 'meow',
rotationCenterX: 20,
rotationCenterY: 400,
imageFormat: 'svg', // 'svg', 'png', or 'jpg'
image: svgString, // svg string or data URI
- rtl: rtl
+ imageId: this.id, // If this changes, the paint editor will reload
+ rtl: rtl,
};
+ this.reusableCanvas = document.createElement('canvas');
}
handleUpdateName (name) {
this.setState({name});
}
handleUpdateImage (isVector, image, rotationCenterX, rotationCenterY) {
- console.log(image);
+ this.setState({
+ imageFormat: isVector ? 'svg' : 'png'
+ });
+ if (!isVector) {
+ console.log(`Image width: ${image.width} Image height: ${image.height}`);
+ }
console.log(`rotationCenterX: ${rotationCenterX} rotationCenterY: ${rotationCenterY}`);
if (isVector) {
this.setState({image, rotationCenterX, rotationCenterY});
} else { // is Bitmap
// image parameter has type ImageData
// paint editor takes dataURI as input
- const canvas = document.createElement('canvas');
- const context = canvas.getContext('2d');
+ this.reusableCanvas.width = image.width;
+ this.reusableCanvas.height = image.height;
+ const context = this.reusableCanvas.getContext('2d');
context.putImageData(image, 0, 0);
this.setState({
- image: canvas.toDataURL('image/png'),
+ image: this.reusableCanvas.toDataURL('image/png'),
rotationCenterX: rotationCenterX,
rotationCenterY: rotationCenterY
});
}
}
+ downloadImage () {
+ const downloadLink = document.createElement('a');
+ document.body.appendChild(downloadLink);
+
+ const format = this.state.imageFormat;
+ let data = this.state.image;
+ if (format === 'png' || format === 'jpg') {
+ data = this.b64toByteArray(data);
+ } else {
+ data = [data];
+ }
+ const blob = new Blob(data, {type: format});
+ const filename = `${this.state.name}.${format}`;
+ if ('download' in HTMLAnchorElement.prototype) {
+ const url = window.URL.createObjectURL(blob);
+ downloadLink.href = url;
+ downloadLink.download = filename;
+ downloadLink.type = blob.type;
+ downloadLink.click();
+ window.URL.revokeObjectURL(url);
+ } else {
+ // iOS Safari, open a new page and set href to data-uri
+ let popup = window.open('', '_blank');
+ const reader = new FileReader();
+ reader.onloadend = function () {
+ popup.location.href = reader.result;
+ popup = null;
+ };
+ reader.readAsDataURL(blob);
+ }
+ document.body.removeChild(downloadLink);
+ }
+ b64toByteArray (b64Data, sliceSize=512) {
+ // Remove header
+ b64Data = b64Data.substring(b64Data.indexOf('base64,') + 7);
+
+ const byteCharacters = atob(b64Data);
+ const byteArrays = [];
+
+ for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
+ const slice = byteCharacters.slice(offset, offset + sliceSize);
+
+ const byteNumbers = new Array(slice.length);
+ for (let i = 0; i < slice.length; i++) {
+ byteNumbers[i] = slice.charCodeAt(i);
+ }
+
+ const byteArray = new Uint8Array(byteNumbers);
+ byteArrays.push(byteArray);
+ }
+
+ return byteArrays;
+ }
+ uploadImage() {
+ document.getElementById(styles.fileInput).click();
+ }
+ onUploadImage(event) {
+ var file = event.target.files[0];
+ var type = file.type === 'image/svg+xml' ? 'svg' :
+ file.type === 'image/png' ? 'png' :
+ file.type === 'image/jpg' ? 'jpg' :
+ file.type === 'image/jpeg' ? 'jpg' :
+ null;
+
+ var reader = new FileReader();
+ if (type === 'svg') {
+ reader.readAsText(file,'UTF-8');
+ } else if (type === 'png' || type === 'jpg'){
+ reader.readAsDataURL(file);
+ } else {
+ alert("Couldn't read file type: " + file.type);
+ }
+
+ const that = this;
+ reader.onload = readerEvent => {
+ var content = readerEvent.target.result; // this is the content!
+
+ that.setState({
+ image: content,
+ name: file.name.split('.').slice(0, -1).join('.'),
+ imageId: ++that.id,
+ imageFormat: type,
+ rotationCenterX: undefined,
+ rotationCenterY: undefined,
+ });
+ }
+ }
render () {
return (
-