Does a Blob and Nat8 work the same way when saving images in a motoko canister?

I am trying to find an proper way of saving images in a motoko canister, I have been using an images type like this:

 public type images = {
        image1 : [Nat8];
        image2 : [Nat8];
        image3 : [Nat8];

I was saving images well, I just had to canvert them to a blob after querying them in my react and then display them, but the problem is that the loading time was very long because of the images, I noticed this because when I didn’t put actual images but just rundom numbers in canding ui, and then some text on other fields which this images type is part of, the querying was just almost instant, but when I save actuall images, the querying time was about 12 seconds at average, sometimes even 15, is that normal?

I then tried to change the Nat8 to a Blob, I was thinking that maybe since the Blob is more compact it can somehow help with the loading time, I set like this:

 public type images = {
        image1 : Blob;
        image2 : Blob;
        image3 : Blob;

But the Blob type is working almost as identical with the nat8, I converterd my image files in my react component to blobs so I can send them to the canister as blobs but still function is only accepting Nat8 values just as I was doing with the Nat8.

So is there any other way I can use to save images with in a motoko canister that will have a faster querying time? I was using a Trie, and then used a HashMap, but the slow querying time is just the same.
Thank you.

I converted to blob because it was a bit faster.

If you don’t have to manipulate the bits, this is likely the way to go.

@quint has a been in this Haskell code lately so he might have some comments on how they are handled under the hood.

12 to 15 seconds sounds too long. Make sure you store in no more than 2MB chunks.

The origyn nft stores and serves images. You can check out that code base to get some tips. If you find any optimizations, let me know.

1 Like

Always use Blob over [Nat8] in Motoko as that is 4x as compact. [Nat8] uses 4 bytes of memory per element.

But that doesn’t explain your query time. Can you share the code of your query function? How large are the images?

Thank you, let me look into it, will update you if I find something working

This is the query function, I’m using a HashMap:

public query func getAllProducts() : async [Product] {
        let productsArray = Iter.toArray(products.vals());
        return productsArray;

The product type:

public type Product = {
        id: Text;
        name : Text;
        price : Int32;
        image : Blob;
        minOrder : Int32;
        shortDescription : Text;
        fullDescription : Text;
        category : Text;
        images : Images;
        additionalInformation : AdditionalInformation;

AdditionalInformation is just text, images are blobs as above,

The image sizes are all ranging from like 10 to 80kB,

Id is uuid

Maybe it is the iter? That doesn’t sound right, but you can test by creating a function that pre calls the array and store sit in another variable…then serve that variable directly…see if there is a difference.

1 Like

How long does it take to query with dfx instead of from react?

Querying the function from command line is taking only about a 1 sec, but from Candid ui and from react, the time is the same 12 seconds

Interesting, then it’s not the canister that takes that long. Something in js does that accepts and deserializes the return value. Maybe someone familiar with those js libraries can look into it.

1 Like