I am new to using blobs and GCS and could do with some help and a sanity check on what I have written.
I am building a web app using Nextjs.
The user can drag an image on to the page.
I want to store the image in GCS.
As the image will only be viewable in the web app, I believe that I want to turn the image into a blob and store that.
To subsequently display the image I just download the blob from GCS when required.
My questions is in two parts:
- A. How to upload a blob to GCS?
- B. How to download a blob from GCS?
My efforts so far are close but something is going wrong somewhere:
- The blob seems to be uploaded and downloaded ok but I cant get the blob to display after retrieval from GCS.
- I am seeing discrepancies in blob size before uploading (size:239536) and after downloading (size: 439114).
- The downloaded blob fails to display after conversion with URL.createObjectURL().
Below is what I have tried so far.
A. How to upload a blob to GCS?
Client-side
First I get the image data from a component and convert to a blob:
// getImageScaledToCanvas(): This returns a HTMLCanvasElement, it can be made into a data URL or a blob
const imgData = ref.current.getImageScaledToCanvas()
imgData.toBlob((blob) => saveImageDataToBucket(blob))
Logging the blob shows:
Blob { size: 239536, type: "image/png" }
Then I execute a fetch to send the blob to my API:
await fetch(/api/saveImageToBucket,
{
method: 'POST',
body: blob
})
.then(response => response.text())
.then(data => console.log('SAVE IMAGE TO BUCKET, fileName=', data))
.catch( err => console.log(err)
)
}
Server-side
The API executes successfully:
try {
const bucket = googleCloudStorage.bucket(bucketName)
const file = bucket.file('myImgBlob)
const stream = file.createWriteStream({resumable:false, gzip:true})
stream.write(req.body)
stream.end()
res.status(200).send('myImgBlob')
}
catch (e) {
res.status(500).json({error: e})
}
Note: Nextjs uses API routes which provide built in middlewares which parse the incoming request (req).
req.body is an object containing the body parsed by content-type.
The file is created on GCS (191.39 KB) and I send the fileName back to the client.
B. How to download a blob from GCS?
Client-side
Execute a fetch to get the image blob from GCS:
await fetch(`/api/getImageFromBucket`,
{
method: 'GET',
})
.then(response => response.blob())
.then(blob => {
const imgBlob = new Blob([blob], {type: 'image/png'})
setTestImage(imgBlob)
})
.catch( err => console.log(err)
)
Logging the blob shows: Blob { size: 439114, type: "image/png" }
Then I just want to render the blob out to a tag to check that all is ok.
const imgUrl=URL.createObjectURL(testImage)
<img src={imgUrl} />
However the image fails to display on the page.
Server-side
The API executes successfully:
try {
const bucket = googleCloudStorage.bucket(bucketName)
const file = bucket.file('myImgBlob')
// Download a file into memory.
//
await file.download()
.then((data) => {
const contents = data[0]
res.status(200).send(contents)
})
}
catch (e) {
res.status(500).json({error: e})
}