forked from external-repos/squoosh
Adding download support. Fixes #47.
This commit is contained in:
14618
package-lock.json
generated
14618
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -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) => (
|
||||||
|
|||||||
Reference in New Issue
Block a user