mirror of
https://github.com/scratchfoundation/scratch-paint.git
synced 2024-12-23 05:52:42 -05:00
Merge pull request #1077 from fsih/filePlayground
Add upload and download image buttons to the playground
This commit is contained in:
commit
7dd437415c
2 changed files with 119 additions and 11 deletions
|
@ -4,7 +4,7 @@ body {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
body, html {
|
body, html, .wrapper {
|
||||||
height: 100%
|
height: 100%
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,3 +13,11 @@ body, html {
|
||||||
width: 90%;
|
width: 90%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#fileInput {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playgroundButton {
|
||||||
|
margin: 4px;
|
||||||
|
}
|
||||||
|
|
|
@ -29,19 +29,23 @@ class Playground extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props);
|
super(props);
|
||||||
bindAll(this, [
|
bindAll(this, [
|
||||||
|
'downloadImage',
|
||||||
'handleUpdateName',
|
'handleUpdateName',
|
||||||
'handleUpdateImage'
|
'handleUpdateImage',
|
||||||
|
'onUploadImage'
|
||||||
]);
|
]);
|
||||||
// Append ?dir=rtl to URL to get RTL layout
|
// Append ?dir=rtl to URL to get RTL layout
|
||||||
const match = location.search.match(/dir=([^&]+)/);
|
const match = location.search.match(/dir=([^&]+)/);
|
||||||
const rtl = match && match[1] == 'rtl';
|
const rtl = match && match[1] == 'rtl';
|
||||||
|
this.id = 0;
|
||||||
this.state = {
|
this.state = {
|
||||||
name: 'meow',
|
name: 'meow',
|
||||||
rotationCenterX: 20,
|
rotationCenterX: 20,
|
||||||
rotationCenterY: 400,
|
rotationCenterY: 400,
|
||||||
imageFormat: 'svg', // 'svg', 'png', or 'jpg'
|
imageFormat: 'svg', // 'svg', 'png', or 'jpg'
|
||||||
image: svgString, // svg string or data URI
|
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');
|
this.reusableCanvas = document.createElement('canvas');
|
||||||
}
|
}
|
||||||
|
@ -49,7 +53,12 @@ class Playground extends React.Component {
|
||||||
this.setState({name});
|
this.setState({name});
|
||||||
}
|
}
|
||||||
handleUpdateImage (isVector, image, rotationCenterX, rotationCenterY) {
|
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}`);
|
console.log(`rotationCenterX: ${rotationCenterX} rotationCenterY: ${rotationCenterY}`);
|
||||||
if (isVector) {
|
if (isVector) {
|
||||||
this.setState({image, rotationCenterX, rotationCenterY});
|
this.setState({image, rotationCenterX, rotationCenterY});
|
||||||
|
@ -67,14 +76,105 @@ class Playground extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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 () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<PaintEditor
|
<div className={styles.wrapper}>
|
||||||
{...this.state}
|
<PaintEditor
|
||||||
imageId="meow"
|
{...this.state}
|
||||||
onUpdateName={this.handleUpdateName}
|
onUpdateName={this.handleUpdateName}
|
||||||
onUpdateImage={this.handleUpdateImage}
|
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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue