Adding download support. Fixes #47.

This commit is contained in:
Jake Archibald
2018-07-02 12:44:20 +01:00
parent 3e26a0a3cc
commit 807a76d443
2 changed files with 24 additions and 14633 deletions

14618
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -27,9 +27,10 @@ interface SourceImage {
} }
interface EncodedImage { interface EncodedImage {
encoderState: EncoderState;
bmp?: ImageBitmap; bmp?: ImageBitmap;
size?: number; file?: File;
downloadUrl?: string;
encoderState: EncoderState;
loading: boolean; loading: boolean;
/** Counter of the latest bmp currently encoding */ /** Counter of the latest bmp currently encoding */
loadingCounter: number; loadingCounter: number;
@@ -51,7 +52,7 @@ const filesize = partial({});
async function compressImage( async function compressImage(
source: SourceImage, source: SourceImage,
encodeData: EncoderState, encodeData: EncoderState,
): Promise<Blob> { ): Promise<File> {
// Special case for identity // Special case for identity
if (encodeData.type === identity.type) return source.file; if (encodeData.type === identity.type) return source.file;
@@ -65,11 +66,13 @@ async function compressImage(
} }
})(); })();
const blob = new Blob([compressedData], { const encoder = encoderMap[encodeData.type];
type: encoderMap[encodeData.type].mimeType,
});
return blob; return new File(
[compressedData],
source.file.name.replace(/\..+$/, '.' + encoder.extension),
{ type: encoder.mimeType },
);
} }
export default class App extends Component<Props, State> { export default class App extends Component<Props, State> {
@@ -132,9 +135,12 @@ export default class App extends Component<Props, State> {
const { source, images } = this.state; const { source, images } = this.state;
for (const [i, image] of images.entries()) { for (const [i, image] of images.entries()) {
const prevImage = prevState.images[i];
// The image only needs updated if the encoder settings have changed, or the source has // The image only needs updated if the encoder settings have changed, or the source has
// changed. // changed.
if (source !== prevState.source || image.encoderState !== prevState.images[i].encoderState) { if (source !== prevState.source || image.encoderState !== prevImage.encoderState) {
if (prevImage.downloadUrl) URL.revokeObjectURL(prevImage.downloadUrl);
this.updateImage(i); this.updateImage(i);
} }
} }
@@ -188,10 +194,10 @@ export default class App extends Component<Props, State> {
this.setState({ images }); this.setState({ images });
let result; let file;
try { try {
result = await compressImage(source, image.encoderState); file = await compressImage(source, image.encoderState);
} catch (err) { } catch (err) {
this.setState({ error: `Encoding error (type=${image.encoderState.type}): ${err}` }); this.setState({ error: `Encoding error (type=${image.encoderState.type}): ${err}` });
throw err; throw err;
@@ -204,15 +210,16 @@ export default class App extends Component<Props, State> {
return; return;
} }
const bmp = await createImageBitmap(result); const bmp = await createImageBitmap(file);
images = this.state.images.slice() as [EncodedImage, EncodedImage]; images = this.state.images.slice() as [EncodedImage, EncodedImage];
images[index] = { images[index] = {
...images[index], ...images[index],
file,
bmp, bmp,
size: result.size, downloadUrl: URL.createObjectURL(file),
loading: image.loadingCounter !== loadingCounter, loading: images[index].loadingCounter !== loadingCounter,
loadedCounter: loadingCounter, loadedCounter: loadingCounter,
}; };
@@ -221,7 +228,6 @@ export default class App extends Component<Props, State> {
render({ }: Props, { loading, error, images }: State) { render({ }: Props, { loading, error, images }: State) {
const [leftImageBmp, rightImageBmp] = images.map(i => i.bmp); const [leftImageBmp, rightImageBmp] = images.map(i => i.bmp);
const anyLoading = loading || images.some(image => image.loading); const anyLoading = loading || images.some(image => image.loading);
return ( return (
@@ -238,7 +244,10 @@ export default class App extends Component<Props, State> {
{images.map((image, index) => ( {images.map((image, index) => (
<span class={index ? style.rightLabel : style.leftLabel}> <span class={index ? style.rightLabel : style.leftLabel}>
{encoderMap[image.encoderState.type].label} {encoderMap[image.encoderState.type].label}
{image.size && ` - ${filesize(image.size)}`} {(image.downloadUrl && image.file) && (
<a href={image.downloadUrl} download={image.file.name}>🔻</a>
)}
{image.file && ` - ${filesize(image.file.size)}`}
</span> </span>
))} ))}
{images.map((image, index) => ( {images.map((image, index) => (