Download .zip of .webp images
This commit is contained in:
@@ -18,6 +18,7 @@ export const Harmonie: Component<{}> = () => {
|
||||
const [getGribList, setGribList] = createSignal<GribMessage[]>([])
|
||||
const [getCanvas, setCanvas] = createSignal<HTMLCanvasElement>()
|
||||
const [getImgList, setImgList] = createSignal<[string, ImageBitmap | undefined][]>([])
|
||||
const [getRefDate, setRefDate] = createSignal('')
|
||||
|
||||
const cachedMessagesSignal = createSignal<GribMessage[]>([])
|
||||
const cachedBuffersSignal = createSignal<Uint8Array[]>([])
|
||||
@@ -71,6 +72,7 @@ export const Harmonie: Component<{}> = () => {
|
||||
getCanvas={getCanvas}
|
||||
options={{ getIsCrop: getIsCrop, getIsContour: getIsContour, getIsInterpolated: getIsInterpolated }}
|
||||
imgListSignal={[getImgList, setImgList]}
|
||||
setRefDate={setRefDate}
|
||||
onClick={getAllGribStructure}
|
||||
/>
|
||||
<ul class={styles.fileList}>
|
||||
@@ -93,6 +95,7 @@ export const Harmonie: Component<{}> = () => {
|
||||
getIsLoading={getIsLoading}
|
||||
getCanvas={getCanvas}
|
||||
getImgList={getImgList}
|
||||
getRefDate={getRefDate}
|
||||
/>
|
||||
<DrawView
|
||||
isLoadingSignal={[getIsLoading, setIsLoading]}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Accessor, Component, createSignal, resetErrorBoundaries, Setter, Signal } from 'solid-js'
|
||||
import { Accessor, Component, createSignal, Setter, Signal } from 'solid-js'
|
||||
|
||||
import { DrawOptions, GribMessage } from './interfaces'
|
||||
import { fetchGribBinaries } from './fetchGrib'
|
||||
@@ -15,6 +15,7 @@ export const ReferenceTimes: Component<{
|
||||
getCanvas: Accessor<HTMLCanvasElement | undefined>,
|
||||
options: DrawOptions,
|
||||
imgListSignal: Signal<[string, ImageBitmap | undefined][]>,
|
||||
setRefDate: Setter<string>,
|
||||
onClick: () => void,
|
||||
}> = ({
|
||||
setIsLoading,
|
||||
@@ -23,6 +24,7 @@ export const ReferenceTimes: Component<{
|
||||
getCanvas,
|
||||
options,
|
||||
imgListSignal: [getImgList, setImgList],
|
||||
setRefDate,
|
||||
onClick,
|
||||
}) => {
|
||||
const [getActiveDate, setActiveDate] = createSignal('')
|
||||
@@ -73,6 +75,7 @@ export const ReferenceTimes: Component<{
|
||||
},
|
||||
).finally(() => {
|
||||
console.log("FINALLLY")
|
||||
setRefDate(refDateStr)
|
||||
const ctx = canvas.getContext('2d')!
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
setIsLoading(false)
|
||||
|
||||
@@ -7,10 +7,12 @@ export const SlideShow: Component<{
|
||||
getIsLoading: Accessor<boolean>,
|
||||
getCanvas: Accessor<HTMLCanvasElement | undefined>,
|
||||
getImgList: Accessor<[string, ImageBitmap | undefined][]>,
|
||||
getRefDate: Accessor<string>,
|
||||
}> = ({
|
||||
getIsLoading,
|
||||
getCanvas,
|
||||
getImgList
|
||||
getImgList,
|
||||
getRefDate,
|
||||
}) => {
|
||||
const [getActive, setActive] = createSignal(-1)
|
||||
const [getIsPlaying, setIsPlaying] = createSignal(false)
|
||||
@@ -60,7 +62,7 @@ export const SlideShow: Component<{
|
||||
|
||||
function download() {
|
||||
const imgs = getImgList().filter(([,img]) => !!img) as [string, ImageBitmap][]
|
||||
downloadImagesAsZip(imgs)
|
||||
downloadImagesAsZip(imgs, getRefDate())
|
||||
}
|
||||
|
||||
return <>
|
||||
@@ -70,7 +72,7 @@ export const SlideShow: Component<{
|
||||
<input type='button' value={getIsPlaying()?'pause':'play'} onClick={play} />
|
||||
<input type='button' value='next' onClick={() => next()} />
|
||||
</div>
|
||||
<input type='button' value='download all' onClick={download} />
|
||||
<input type='button' value='download .zip' onClick={download} />
|
||||
</div>
|
||||
<ul class={styles.slideShowList}>
|
||||
{ getImgList().map(([forecastDate, img], i) =>
|
||||
|
||||
+62
-43
@@ -1,46 +1,65 @@
|
||||
export async function downloadImagesAsZip(images: [string, ImageBitmap][]) {
|
||||
downloadCompressedImage(images[0][1], '00.gzip')
|
||||
import JSZip from 'jszip'
|
||||
|
||||
export async function downloadImagesAsZip(
|
||||
images: [string, ImageBitmap][],
|
||||
filename = 'images',
|
||||
): Promise<void> {
|
||||
filename = filename + '.zip'
|
||||
const strBlobArr = await Promise.all(
|
||||
images.map(async ([bitmapName, bitmap]): Promise<[string, Blob]> => {
|
||||
const blob = await bitmapToBlob(bitmap)
|
||||
return [bitmapName+'.webp', blob]
|
||||
})
|
||||
)
|
||||
|
||||
const content = await createZip(strBlobArr)
|
||||
|
||||
download(content, filename)
|
||||
}
|
||||
|
||||
async function compressImage(bitmap: ImageBitmap): Promise<Blob> {
|
||||
// First convert ImageBitmap to WebP using canvas
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = bitmap.width;
|
||||
canvas.height = bitmap.height;
|
||||
function bitmapToBlob( bitmap: ImageBitmap): Promise<Blob> {
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = bitmap.width
|
||||
canvas.height = bitmap.height
|
||||
const ctx = canvas.getContext('2d')!
|
||||
ctx.drawImage(bitmap, 0, 0)
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) throw new Error('Could not get canvas context');
|
||||
|
||||
ctx.drawImage(bitmap, 0, 0);
|
||||
|
||||
// Get WebP blob
|
||||
const webpBlob = await new Promise<Blob>((resolve) => {
|
||||
canvas.toBlob((blob) => {
|
||||
if (blob) resolve(blob);
|
||||
}, 'image/webp', 0.8); // Quality 0.8, adjust as needed
|
||||
});
|
||||
|
||||
// Convert Blob to ReadableStream
|
||||
const webpStream = webpBlob.stream();
|
||||
|
||||
// Apply GZIP compression
|
||||
const compressedStream = webpStream.pipeThrough(
|
||||
new CompressionStream('gzip')
|
||||
);
|
||||
|
||||
// Return as Blob
|
||||
return new Response(compressedStream).blob();
|
||||
}
|
||||
|
||||
// Usage example:
|
||||
async function downloadCompressedImage(bitmap: ImageBitmap, filename: string) {
|
||||
const compressedBlob = await compressImage(bitmap);
|
||||
|
||||
const url = URL.createObjectURL(compressedBlob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = filename;
|
||||
link.click();
|
||||
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
return new Promise<Blob>((resolve, reject) => {
|
||||
canvas.toBlob(
|
||||
(blob) => {
|
||||
if (blob) resolve(blob)
|
||||
else reject(new Error(`Failed to convert blob to WebP`))
|
||||
},
|
||||
'image/webp',
|
||||
0.8
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export async function createZip(blobs: [string, Blob][]) {
|
||||
const zip = new JSZip()
|
||||
|
||||
blobs.forEach(([name, blob]) => {
|
||||
zip.file(name, blob)
|
||||
})
|
||||
|
||||
return await zip.generateAsync({
|
||||
type: 'blob',
|
||||
compression: 'DEFLATE',
|
||||
compressionOptions: {
|
||||
level: 6
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function download(content: Blob, name: string) {
|
||||
const downloadUrl = URL.createObjectURL(content)
|
||||
const link = document.createElement('a')
|
||||
link.href = downloadUrl
|
||||
link.download = name
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
|
||||
URL.revokeObjectURL(downloadUrl)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user