Skip to content

Commit d9512d7

Browse files
committed
feat: add webp support
1 parent 5311631 commit d9512d7

7 files changed

Lines changed: 41 additions & 3 deletions

File tree

packages/scratch-gui/src/components/sprite-selector/sprite-selector.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ const SpriteSelectorComponent = function (props) {
120120
title: intl.formatMessage(messages.addSpriteFromFile),
121121
img: fileUploadIcon,
122122
onClick: onFileUploadClick,
123-
fileAccept: '.svg, .png, .bmp, .jpg, .jpeg, .sprite2, .sprite3, .gif',
123+
fileAccept: '.svg, .png, .bmp, .jpg, .jpeg, .sprite2, .sprite3, .gif, .webp',
124124
fileChange: onSpriteUpload,
125125
fileInput: spriteFileInput,
126126
fileMultiple: true

packages/scratch-gui/src/components/stage-selector/stage-selector.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ const StageSelector = props => {
102102
title: intl.formatMessage(messages.addBackdropFromFile),
103103
img: fileUploadIcon,
104104
onClick: onBackdropFileUploadClick,
105-
fileAccept: '.svg, .png, .bmp, .jpg, .jpeg, .gif',
105+
fileAccept: '.svg, .png, .bmp, .jpg, .jpeg, .gif, .webp',
106106
fileChange: onBackdropFileUpload,
107107
fileInput: fileInputRef,
108108
fileMultiple: true

packages/scratch-gui/src/containers/costume-tab.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ class CostumeTab extends React.Component {
351351
title: intl.formatMessage(addFileMessage),
352352
img: fileUploadIcon,
353353
onClick: this.handleFileUploadClick,
354-
fileAccept: '.svg, .png, .bmp, .jpg, .jpeg, .gif',
354+
fileAccept: '.svg, .png, .bmp, .jpg, .jpeg, .gif, .webp',
355355
fileChange: this.handleCostumeUpload,
356356
fileInput: this.setFileInput,
357357
fileMultiple: true

packages/scratch-gui/src/lib/file-uploader.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {BitmapAdapter, sanitizeSvg} from '@scratch/scratch-svg-renderer';
22
import randomizeSpritePosition from './randomize-sprite-position.js';
33
import bmpConverter from './bmp-converter';
4+
import webpConverter from './webp-converter';
45
import gifDecoder from './gif-decoder';
56

67
/**
@@ -122,6 +123,12 @@ const costumeUpload = function (fileData, fileType, storage, handleCostume, hand
122123
});
123124
return; // Return early because we're triggering another proper costumeUpload
124125
}
126+
case 'image/webp': {
127+
webpConverter(fileData).then(dataUrl => {
128+
costumeUpload(dataUrl, 'image/png', storage, handleCostume);
129+
});
130+
return; // Return early because we're triggering another proper costumeUpload
131+
}
125132
case 'image/png': {
126133
costumeFormat = storage.DataFormat.PNG;
127134
assetType = storage.AssetType.ImageBitmap;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export default webpImage => new Promise(resolve => {
2+
const imageUrl = typeof webpImage === 'string' ?
3+
webpImage :
4+
window.URL.createObjectURL(new Blob([webpImage], { type: 'image/webp' }));
5+
const canvas = document.createElement('canvas');
6+
const ctx = canvas.getContext('2d');
7+
const image = document.createElement('img');
8+
image.addEventListener('load', () => {
9+
canvas.width = image.naturalWidth;
10+
canvas.height = image.naturalHeight;
11+
ctx.drawImage(image, 0, 0);
12+
const dataUrl = canvas.toDataURL('image/png');
13+
window.URL.revokeObjectURL(imageUrl);
14+
resolve(dataUrl);
15+
});
16+
image.setAttribute('src', imageUrl);
17+
});
2.41 KB
Loading

packages/scratch-gui/test/integration/costumes.test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,20 @@ describe('Working with costumes', () => {
161161
await expect(logs).toEqual([]);
162162
});
163163

164+
test('Adding a webp from file', async () => {
165+
await loadUri(uri);
166+
await clickText('Costumes');
167+
const el = await findByXpath('//button[@aria-label="Choose a Costume"]');
168+
await driver.actions().mouseMove(el)
169+
.perform();
170+
await driver.sleep(500); // Wait for thermometer menu to come up
171+
const input = await findByXpath('//input[@type="file"]');
172+
await input.sendKeys(path.resolve(__dirname, '../fixtures/webpfile.webp'));
173+
await clickText('webpfile', scope.costumesTab);
174+
const logs = await getLogs();
175+
await expect(logs).toEqual([]);
176+
});
177+
164178
test('Adding several costumes with a gif', async () => {
165179
await loadUri(uri);
166180
await clickText('Costumes');

0 commit comments

Comments
 (0)