Add upload and download image buttons to the playground

This commit is contained in:
DD Liu 2020-05-24 18:21:26 -04:00
parent 87e01639c0
commit 2e88b6d070
4 changed files with 133 additions and 16 deletions

View file

@ -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)

View file

@ -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,

View file

@ -4,7 +4,7 @@ body {
margin: 0px;
}
body, html {
body, html, .wrapper {
height: 100%
}
@ -13,3 +13,11 @@ body, html {
width: 90%;
margin: auto;
}
#fileInput {
display: none;
}
.playgroundButton {
margin: 4px;
}

View file

@ -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 (
<div className={styles.wrapper}>
<PaintEditor
{...this.state}
imageId="meow"
onUpdateName={this.handleUpdateName}
onUpdateImage={this.handleUpdateImage}
/>
<button className={styles.playgroundButton} onClick={this.uploadImage}>Upload</button>
<input id={styles.fileInput} type="file" name="name" onChange={this.onUploadImage} />
<button className={styles.playgroundButton} onClick={this.downloadImage}>Download</button>
</div>
);
}