This video demonstrates how to implement client-side image resizing using WebAssembly (Wasm) in the browser, showing how to load Wasm modules, manage memory between JavaScript and Wasm, process image data (RGBA format), and implement a naive resize algorithm that samples pixels from the input image to create a smaller output image, all without relying on the browser's canvas API for the actual resizing operation.
Client-Side Image Resizing in WebAssembly: A Technical Guide
Added:Yo yo yo, what's up? What's up? What's up everybody? Welcome back. Uh today I want to work on uh client side image down sampling in Wim in the browser. Uh context here is uh I'm working on this like little web app whose goal is to like track uh food that I have, right?
And one of the things that we might do in here is we might have uh multiple types of bread, right? And so maybe um I'll have like a loaf of the Wonderbread from the store and a loaf of some other bread also from the store. And you know, I don't really know what their names are. I don't really want to think about it. Um but I I can identify by like picture pretty easily. It turns out that we look at a lot of pictures during the day. Probably like millions of them if you like to have some frame rate in your eye. I don't know, man. Um so I think that I want like picture of thing, right? But my phone, if I were to like just like take a photo on my phone and upload it, it would be like mega big.
Way too big. I only need like a [ __ ] like 600 by 600 image. Probably even less, right? I just need like Which one is that? Is it blue? I like blue. Well, blue bread would be moldy as [ __ ] but maybe the packaging is blue or something, right? And I just want like picture see picture. Um, this is kind of like a stepping stone into some other stuff, too. Like what I also want to do is like client side barcode decoding.
Um, so this is kind of like a nice little excuse to get uh an image into Womland and play around with it. Um, but yeah, so big picture, way too big.
Before we upload to the server, I want to like make it small. Um, I will note that, you know, if you Google how to resize an image in JavaScript, people will tell you to use a canvas and it's like that's reasonable, right? The canvas will like, you know, the browser written in C++ will like do some efficient downsampling. Um, but I don't want to do that, okay? You can't make me. this is my stream. I can make whatever bad decisions I want. Um, and so that's the plan. Try to get some sort of image downsampling. So, plan of action is, you know, we need to like get little a little Wom hello world up and running. We need to like get the image data and get it into Womland, implement like a really stupid simple uh resize, and then we're done. So, let's just kind of like get moving and grooving and see what happens. Um, so I guess let's get a second little window open for uh a little test page. So let's do a little uh let's do a little copy paste of something into test HTML, you know, do a little test HTML read me.
Thanks for tier one. Much appreciated.
And uh I guess we're going to be like, "Hello world." And let's go there and see what happens. Uh okay. Boom. Hello world. Hello. Um so I guess we need to get Wom in here somewhere, right? So presumably we need some JavaScript.
Uh test js probably deferred.
And then we need to edit that thing. Uh console log hello world. Cool. And so now if we go in here and we refresh, hopefully we see hello world. Hype.
We're running some JavaScript. Hello.
Hello. Hello.
Is that like Australian accent? Hello.
kind of um okay so we need a WOM file to load from JavaScript land presumably uh which you can do in Zigg I just don't really remember how but it's okay we'll figure it out uh let's do wom test zigg here and we can just do like pub function export function probably uh and let's just do like a little quick little adder so we'll take in like two ins uh a i32 b i32 and he's going to return i32 and let's uh do a little return a plus b. That's a simple little hello world. Uh we need to compile this thing.
So presumably we need some sort of like wom target to compile for which I think it's like parse target query or what is like what is a target in this world? I remember there's a way to like create one of these things. Resolved target from a query. Um, you know what? I'm going to cheat and I'm going to look at what we did for the ball machine.
Uh, here we did. Oh, this is uh deprecated. Cool. Uh, use stood target query. Okay. Uh, but we did something that's like similar to this.
Uh so can we do something like stood target query um parse?
Yeah. Yeah. Yeah. Yeah. Yeah. Yeah.
Uh no.
Okay. Zigg Wom.
Let's uh just see what someone else has done.
Uh because I don't want to do this. Zigg wam build zig. Somebody somebody must have done this recently. What year is this? Last year feels like maybe out of date, but we'll see.
Um here. Okay, this is what I want. Huh?
This is what I want. Wom target huge for us. And then I remember that there's some sort of like options you have to set on this [ __ ] R dynamic sounds familiar and maybe entry disabled but we'll see.
Uh, wom.exe is in uh create uh hello, I can't remember. Add executable.
Okay. And we're going to be like b path uh source wom test. Nice. Uh target is equal to wom target hype. And optimize equal to this whatever our optimize level is.
Uh, did you try Zig's self back end? I'm on I'm on the latest release, so I'll try it when it comes out.
I'm kind of okay with that, you know.
I'm okay with it. Okay.
Uh, so if I build this, let's just see what happens. Uh, root source file, not path. My bad. My bad.
I can do master branch if I want. I just don't. It's not worth the effort for me.
I'd rather just be on Liz release. Uh, okay. So, we need to set that there's a entry, no entry, and then I think you need to specify R dynamic to get it to actually export the symbols if they're unused.
I think I don't really remember what R dynamic does, but I seem to remember this being like a big deal.
Um, and then there's like tools. Wom like dump wom to watt I think is the tool to like see what the [ __ ] it made.
I think that sounds familiar. Sounds familiar.
So, we should be able to see in here uh Wom to watt on zig out bin wom test.
So, that is a really good sign. There's like stuff in here. lots of stuff. And specifically, there's an exported function add, which is huge for us, which looks, you know, there's a lot of extra garbage in here, huh? But it's fine. It's fine. Uh, okay. How big is that thing?
700 678K. But I assume that if we did like uh if we set this to like release small, I bet you it's a lot more sane, right? I bet you that a lot of this is like lack of stripping and all that [ __ ] So we could probably tune our build options to get a little better.
But yeah, if we look at the wom to what of this guy now look at that. That's way more sane, right? We have a function add whose function zero. And it's literally like get the first parameter, get the zero parameter, and then add.
Uh, so yeah, I'm going to go back to debug mode though because I don't give a [ __ ] Um, but we could do it that way if we wanted. Uh, y back was your answer, XD. Yeah, I mean it was just that like I don't I don't run master and I could, but I don't. I'm like okay with being a little behind, you know. I'm okay with it. Uh, okay.
So, can we instantiate this web assembly module in our test js?
Um, so we probably want to do like uh async function in it so that we can do some async stuff. We do window onload is equal to init. And here we go.
Uh, I missed like one stream and you're already adding Wows to the food website.
There there was kind of like a zero to 100. There was no leadup, so don't worry about it.
Um, okay. Web Assembly instantiate streaming. This sounds right. Uh, how the [ __ ] does this work?
We should look it up. Web Assembly MDM.
Let's like look for like a quick little example.
um guides.
Uh loading and running Web Assembly using the Web Assembly JavaScript API. This sounds like what I want. Uh Web Assembly and Statate streaming with the result of fetch with an import object. Right? So import object is kind of like all the [ __ ] you want to inject into your web assembly module if I remember correctly.
Um, but I think right now we don't need anything, so we won't.
So, this is going to be like, uh, I guess our server needs to put this somewhere, huh?
Yeah. So, we kind of need this to go. We need like we kind of need to like just make a custom endpoint for it. That's fine.
That's fine.
um with no import object and this guy is like uh we have our Wom equals this and then we want to call into this guy. So we have like instance exports and the export function is add. So we want to do like add one and two and console log that thing and we're hoping to get three out.
Uh so before we do that we need to you know quickly just add a little getter for this thing. So what do we call it? We called it uh wom test wom. And if we have a get of test wom it's like a file system of uh zig out bin test wazom wom something right something like that okay so localhost 9990 test wom uh he doesn't like Um, weird.
I would think that works. I would think.
Okay. So, what's he complaining about for real? He's saying file not found.
Um, is it because the file system stuff always prefixes it with like res? It might. It might uh Let's see. What are we doing here? Yeah, cuz we're like doing relative to the resource there. Fine.
We'll do it like this.
just copy paste whatever the [ __ ] we were doing there and use uh stood fs current working directory and then not think about it because this is not what we're trying to accomplish today. This is just a hack.
We're [ __ ] hacking.
Okay, let's try that.
Come on. Just give me the [ __ ] [ __ ] wom, please. File not found. Are you kidding me?
Why?
Um, can we log this thing stood debug print wom time with this?
Please God, this is not the interesting part of today. Just get it out of my way.
Uh, so he does say wom with zig out bin test wom. Is that the wrong file?
Uh, yeah, that would do it, huh? Wasn't test.
Fine.
Fine. If you want to be like that, if you want to be like that, I'll [ __ ] put the right file in. Um, okay. So, now that does exist, but he's still [ __ ] falling over.
Did I do something wrong here?
Current working directory read file.
Uh yeah.
Yeah, there's no like there's no like URL parsing to do. I see. We were doing some like intentional stripping stuff.
Okay, cool. So, we can get the file now.
We get the file now, which is hype. So, now if we go back to our little JavaScript land, test.js, notjson. Thank you. Uh, this guy should do something.
Uh, okay. Uh, response has unsupported mime type expected application wisom.
Fine.
Are you serious? We need the right [ __ ] mime type.
Uh, fine.
Fine.
If you want to be like that, we'll [ __ ] do it. We'll [ __ ] do it if that's what you need from me. There we go. Three. So huge.
So huge.
So we got number three right here. So what are we going to do now? We need to I guess uh get some image data into this thing, right? So WAM memory model is kind of there's like two models. One is that like the browser in JavaScript you like allocate a hunk of memory and you feed that to the executable. The other option is that like Zigg will generate some web assembly instructions that will ask the browser to give it some memory.
And that's the world that like the default Zigg executable lives in. Um there's like this like instruction that you can emit that's like hey I need some memory. And then like the allocators kind of like call that instruction if they need to. Um and then that is exposed as an export.
Um so if we are trying to like feed data into this thing, we need to like look at that chunk of memory and put like somehow parse the uploaded file and then put it in there. So let's do that. Um, I think what makes sense is to maybe like lazily load this thing. It really depends on like what the file API is. I guess what we can do is what we can do an async function upload file and this is going to take in like data probably as well as a I think it's like this as well as a size.
Okay.
And what wait why is it mad?
Is this not the syntax for a pointer? Am I [ __ ] high?
I thought that this was the syntax for multi-element pointer. Am I Oh, I'm in [ __ ] JavaScript. I'm a dumbass, dude.
My brain just was not parsing.
Okay. So, let's do something that's like a set file content and we'll take it a data and a size and we will return nothing. And then what we'll do is we'll probably have like some sort of like global buffer that we use um that we'll just replace the contents of. Um so can we do something like this global like content buff is you know u8 slice u8 yeah u8 slice of this by default right and what we'll do is we'll say like if content buff len is less than size uh we can free it and replace it with a new one.
Yeah. Yeah. Alec. Alec. Uh size.
Okay. And then can we just do like Alec is uh we need the stand library.
Uh so we stood heap wom allocator I guess on both of these guys.
And if this fails we just freak the [ __ ] out I guess.
And then content buff, we equal this.
Okay.
Then we just do like a mem copy from data zero to size into the content buff, right?
Uh this is actually probably the wrong way to do this. This is wrong because this means that like this pointer needs to exist in web assembly memory in which case the data is already in web assembly memory. So what the [ __ ] are we doing?
Right? This should be uh set content size like this.
And then we should copy the data in from JavaScript land. That makes more sense.
So what we what we should do is we should have like a uh get content buff and this is going to return a pointer and this is just going to return content buff pointer. So I think the workflow here is we ensure that there's enough enough room for the file that we want to upload. Then we put it in here and then let's do like uh you know I don't know I guess having some sort of like print mechanism is ideal so that we can like print something about it. So I think to do that you do like export function or um extern function print and this thing is going to take a like data and len and we need to set up some JavaScript to print this stuff for us right so uh let's do a little uh this is going to be like let me think for a I want a function that will like format data and try to print it like that. So I think that we can just do something a little simple like have um print internal or something whatever that's going to take in like a format uh and args, right? And this guy's going to be like uh I'm going to have like a buffer here.
Just like a 4K buffer.
And we're going to do a buff print into this thing. So we're going to be like get into that bad boy with these args.
Uh and we'll say like slice is this. And if this fails, uh we'll just return like the whole buffer.
Um, and then we'll try to print this thing.
Okay, cool. So, can we do like print internal just like the result of the ad and see what we get?
That'd be kind of sick.
Um, he's mad because this probably needs to try and then uh Oh, no. It's a catch here. That's why. catch buff.
Okay, then this thing actually should never error. So we go like this and then we should be chilling.
Okay, so that compiles supposedly if we did everything right. And when we refresh this thing, he says uh import object does not have m. So we need to in JavaScript like inject a print function.
Uh, so we go.
Oh my god, I'm gonna freak out about loading test JSON over and over again.
So here we need like env. And I guess we'll just like kind of continue down this thing until it stops complaining at us.
Uh, so print is not a function. So here I assume that we do like print, right? and then takes in a, you know, pointer and a len, right? So, we're gonna have to do something with this console log pointer len. Let's just see like what comes out of that thing. Okay, so that's good. So, we got a pointer into web assembly memory and a length of a string. Um, and so we just need to do something with that. So, I think what I usually do here is I make like a global WM object.
uh that's null by default.
Then here we assign it like this. And then when we call print we can like look at that thing. So we can look at uh this thing is uh web assembly or something. Or maybe it'll figure it out for us. Let's see. No.
Uh I guess we can do like if wom object equals null return just to get like the the language server understanding what's going on. If I just do this do I get instance what is this thing? What does this return?
Web assembly instantiated source.
Yeah, here we go. So, we have this exports of memory if I remember correctly. If I remember correctly.
Yeah. So, we have a memory chunk and so there's a way for us to like extract information from that memory. I just don't remember what it is. Maybe a buffer.
That sounds familiar. Yeah. Okay. So, we can like look at this buffer and find the pointer in it. So, I think it's like UTFA.
No h array from this I think.
And then we should be able to like slice this thing from pointer to pointer plus line or something.
Uh returns a section of the array. So from the start to the end. Yes. And so then we should be able to do something like make a text decoder and turn this into something.
What does this take in input? So, like this. I think I'm not 100% sure on this.
I might be like doing some unnecessary copies and stuff, but I think this is right.
Let's just see what that does. Oh, let's [ __ ] go, dude. We guessed right. I'm We might be doing something like blatantly inefficient there. There might be some like copies there that I'm not seeing. Um, but at the very least, we have the ability to print from Zigglland now, which is hype. I'm not really too worried about if that's like super wrong right now.
Um so what I would love to do is I would love to um print like the content buffer uh like like maybe do something like uh buff ready or something. Right. So, we're going to like set the content size from JavaScript land. We're going to put the content in there, and then we're going to be like, uh, buff ready. Like, do your thing.
Do your [ __ ] thing, right? And so, here, let's just for now, um, print this thing.
So, can we just like print internal some string, which is the content at content buff?
You know what I mean? That seems kind of reasonable, which means that we can like kind of test the interfacing with memory. Um, okay. So, we're going to be like womob instance exports set content size to uh 50.
Okay.
Then we're going to get the content buff.
So we go, "Hey, will you have some memory for me? Please get it."
And then is this happy hour the full focus of the day? Uh, probably full focus. This seems very YouTubable.
Uh, but I think that we might do we might we might transition into like a post this happy hour depending on how quick this goes. We'll see.
slash how I'm feeling.
Um, okay. So then we need to like put stuff in here. So this is where we have to like actually confirm what this like u array does, right? Can we just like construct a array and put stuff in there? You know what I mean?
Uh so if we use the buffer constructor dude hello cyped array that's I don't think what I want because that would be this one right from an array buffer. Like where does it tell me what it does? Am I [ __ ] high?
Like, okay, buffers. There are array buffers and shared array buffers. Both are level representations of memory span. They have array in their names, but they don't have much to do with arrays. Cool.
That's sick. Love that. You cannot read or write them directly. Instead, buffers are generic objects contain raw data.
Uh, so then, oh, copy is slices. Copy.
That's not good.
Views.
Um, so typed array views in it array is a view into a thing. Okay. Uh, subarray creates a new typed array that references the same buffer. So we probably should have done like here this slice should have been like subarray probably.
Probably. So let's make sure that does the same thing cuz that's kind of more analogous to what we're going to be wanting to do later. So here we're going to be like um this is a content buff pointer and we're going to want like the content buff as a unit and data array, right? So we're going to be like uh content buff is going to be um we're going to get the memory out of this guy.
Memory buffer and we're going to like It's probably like this, right? And then we have like content buff is wom memory sub array from content buff pointer to content buff pointer plus the length.
Right? So here we have len is 50 and we said that here and then can we put like can we do like uh like a text in code maybe?
So let's like take some can we do like encoder encode into hello world into content buff then call wom ob instance exports buff ready I think that's what we called it uh subarray is not a function Uh yeah, true.
Can I just like directly construct this unit data array using some slice of the buffer buffer bite offset length? Yeah, surely right. So surely we should be able to go like uh content buff pointer len like this just directly.
Okay. So that's good. That's good. We do see the hello world make it in and out of Womland. So that's super big. Super big for us. These are probably all of the like zig standard like 0xa default allocation.
Uh but this is looking pretty good. Uh yeah. So this we can actually do here as well. Pointer pointer plus len. Then we can just use array directly here.
Out of bounds you 8 array. Whoa.
Oh, because this should be uh len here, not pointer plus len. Nice. Okay, cool.
I think we understand. So now the next thing is to uh get like image data into this thing.
So we'll call that last section uh interface with wom memory.
Uh and then we'll do uh what do we call it? Get image data.
So, I don't really know how the [ __ ] this works.
Uh, I think you do like file upload input hint like a like an input for file and then just like upload the file data directly. I think that's usually how like image upload works.
Um, so that means that like we have two options here. One is trying to use browser APIs to like extract the pixel buffer. What you would do there probably is use like an HTML canvas um load it with image data and then read it back. But if we're going to do that, like we're trying to dodge the canvas.
We already we're intentionally not using the canvas. So probably the other option here is like giving it PNG data and then asking STB image or something to decode it. As long as we can get STB image into Web Assembly land, that should be fine.
So that's probably the first thing to try there. You know, SV image is like just like a raw C implementation of uh reading images.
Uh that's like a nice little you can just like copy paste it into your project, which we love around here sometimes. And then I assume that we can I assume we can override things to the point where we don't need like lib C or anything.
I'm pretty sure that's possible, but we should we should double check that.
Um, okay. So, let's do uh how do you we do this in zigland?
Usually it's like we do like a add c source file and his file is bpath uh stbb image C.
We usually do this because um it's the Zigg C parser is like in my experience in the past hasn't been good enough to like compile full-on STB image.
Uh so let's do this. And then we do STB image C. And this guy just includes STB image.h. Can you do like this?
Uh I think this is fine. And then we we define uh hold on it tells you how define the implementation here.
Okay.
And then we have to do like wom exe add include path to uh be path root.
And then we should be able to in our wom test do like uh you know stb image is a c import image.h okay so right now what happens I don't know.
Okay. So, he's mad that there's STDI on here. That makes a lot of sense.
So, let's try to like get this thing out of here. So, can we do like Wom exe?
I think it's here.
Um, we have to be careful about like matching the includes here. Oh, but maybe you only need this on the implementation. Some of these things you probably do. So, let's start there. Um, STBA image C. So we'll define SVI. No studio.
Try building again. Stood lib not found.
Looks like we can't get away with no standard library.
Interesting.
If we just comment this out. Let's just see how far that goes.
This one maybe.
I assume this will cause us problems, but yeah. Okay. Um, maybe this is not as simple as I would have liked.
I assume that I can't just do this, right? Wasn't easy link lip. I assume that that'll fall over, but maybe not.
If they're only using header stuff, then maybe it's okay.
Uh stood live. Yeah, not so lucky.
So how um is this kind of just unconditional?
This looks like Okay, I'm down to try just commenting this out again and see where it goes.
string.h as well. Yeah. So unlucky.
Okay. Uh what do I want to do here? I could have sworn that this was like possible.
But if it's not easy, um then we're going to have to try something else. We can we can I'm like almost certain this is possible, right? Because the vast majority of the stuff it needs should only be like headers, right? So, we must be able to like tell it that that's okay. I just don't know how to do that right now. Um because then you could also like like implement when it's like I'm trying to link me copy. We could just like write our own version of me copy and that'd be fine.
Wait, have we done this before? This sounds really familiar. I think we did this in ball machine.
Did we find dot dash name SCB image?
No.
Okay, maybe not then. Maybe not. So, okay, what we'll do for now is we'll cheat.
We'll use the canvas API to get the image, but we'll do the downsampling in WOM. And then later, um, I'm going to loop back to try to figure this part out just because this isn't really like the like the interesting part necessarily.
And I don't really want to fight with build systems right now.
Um, but I do believe it's possible. I will I will make that clear.
Um, okay. Are we back?
home.
All right.
Uh we're still back. Uh so let's use canvas API to decode an image.
Uh get image data. I think it's possible.
Get image data uh returns an image data object which I assume that you can get a U and 8 array out of.
Yeah.
And then you should just be able to like copy this thing with that.
So, can we do something like uh let's just do this canvas.
Let's uh just paint a red blob on there.
like this.
Yeah. So, we'll be like in here.
We'll do HTML canvas element. Boom.
Uh document get element by ID canvas.
And we'll just kind of paint something red there and see what happens.
canvas uh get context 2D rendering context, right? Something like this.
And then it's like ctx fill rect from 00 to 800 by 800. And we just want to fill this thing with uh fill style. I think like we're like this. I think this will make it red if I remember correctly.
Uh yeah, hype. So we got a big red box.
And we can hopefully feed this somehow.
So they're claiming we can do this.
Uh get image data mtn. What's the API here?
Um top left. Yep. width and color space gives us sRGB. Uh this returns image data which we can look at. So can we do like image data dot data and can we like can we copy from like how does that work? 8 array copy JavaScript Um like co like me copy like am I [ __ ] stupid for this is the same [ __ ] page. So I want like copy into or something. Copy into 8 array. Copy into existing inate array.
That must exist. I just don't know what the [ __ ] method is.
Copy, dude. Surely, right?
Um, dude, I mean, copy within is close probably, but this is in the same typed array. I want to go from like somewhere else.
Is this really not [ __ ] possible?
Yes. Well, please don't call me Shirley.
It's a classic.
Uh set set.
Okay, let's look at that. Uh, u 8 array set MDN.
Dude, what the [ __ ] is this? Like, does it inherit from something?
Maybe it's in here.
Looks like it's sorted by name. Set.
Aha. Here we go. Instances stores multiple values in the typed array reading input from specified. Yep, nice.
That's exactly what I want. So, we want to be able to do like uh we want to set the length of the stuff in web assembly land to image data data length bite length probably, right?
Then I guess we can actually do it like this.
Okay. And then instead of doing text encoding, we do like content buff set from image data data, right? Just [ __ ] like rip that [ __ ] Kind of down to see what happens.
So, we do get a bunch of garbage. Um, but it might be interesting to see what that garbage looks like, right? So we probably have like here can we print out this thing as numbers.
Okay, that's looking promising, right?
FF00 FF FF 00 FF. So this is RGBA RGBA RGBA probably, right? So if we change this to uh red and blue makes or red and green makes yellow um we should figure out bite order, right? So if we go from wherever the [ __ ] we were filling this in with red and change this to yellow, we should see the first two.
Yeah. So we're seeing RGBA.
RBA. That's really big for us.
Uh, I think Zigg image lib is often used instead of stb image. No libc as far as I know. That's pretty sick. That's pretty sick. A good a good fix.
A good fix. But we'll start we'll start here since we're already we've already done it.
Um, okay.
So, let's do something with this. I don't know what yet.
Um, it would be nice to get like a more interesting image in here.
So, I think what you can do is you can like load image into canvas.
You can like just draw image.
Draw image like this.
Sure.
Uh new I think you like canvas draw image from file input. There's like a way to do it this way where you just have like the data directly.
Uh I see.
I see. Okay. So, if we want to do something like create object URL to get a URL referencing a blob.
Nice. Okay. So, we do if we want to like upload a picture. We want to upload a picture. We go like this.
Input type equals file.
Uh ID is equal to like file upload or whatever.
Uh I think it's actually just like thisump.
Okay. So in here we should be able to do something like uh we have a HTML input element file upload is whatever the [ __ ] we called it which was the exact same thing here.
Uh we can go like file upload.
Uh it's like on something uh uh input HTML input element on probably on change, right?
probably stood debug or console log evv target file zero. Let's just see if that gives me kind of what I expect which is some sort of content or something.
Uh okay. So this gives me a file with name.
Nice. And then how do I like convert that? He's saying I can just use URL create target. So he's saying like if I were to do something like inject uh an image element into the DOM here just as like a quick test. Um he's saying that I can do like URL.create object URL from this thing, right?
Uh, and then that should like display if we do like document body append image if I understand this correctly. And then let's find a test image that doesn't suck.
What if I what if I Google image picture?
Uh, save image. Perfect. as in downloads and can we upload that thing now? If I refresh and I browse and I go to downloads and take that picture. Um, create element is not a function. That's true.
You don't you're not going to do me like that. Okay. Huge. So, we know how to like uh extract the the image data from here kind of. This creates an object though and we need to feed this into the canvas.
So you set the image like this instead.
You go like this is a new image and then we're going to like fill or draw image with image. Right?
So he's saying I have to do this with in a callback which is fine.
Uh 800 800 maybe. What is CEX drawing to take?
Maybe maybe where it's drawing maybe.
Let's see what that does.
Uh jack [ __ ] Huh.
drawing.
He is not doing anything.
So, that doesn't do what I expected.
Um, yeah. What the [ __ ] What the [ __ ] This feels reasonable. No.
Um, you need to reset the file. That's a really good point. I did just not do that part. There we go. Okay, so he's in the canvas now. Hype. Thank you. Thank you. I was like felt like I was losing my mind.
Okay, so now we have a thing that we can feed into Womland.
Okay, cool.
So, what are we going to do? I guess try to do a resize.
So, [Music] I don't know. I haven't really thought about this part yet.
I guess we're going to like maybe call this like do resize.
And this is probably going to return uh I don't know if it's like trivial to get multiple return values out of here. It might make sense to do like get resize buff like this and get resize len right and in here we have like resize buff And we like calculate the size of this based off of that. Why is he mad here?
Oh, just cuz we didn't return. Sure.
Okay.
Right. So then we can kind of do the resize. And what are we going to do there is like we're going to calculate the size of that thing based off the size of the content buffer probably.
So we have like pixel format is RGBA.
We understand that.
Um so I guess here we're going to have like a desired width and height.
Um and when we we're going to have like old width and old height probably, right?
We actually can derive the height based off this. And we can derive we can probably derive the height based off only this, right?
Yeah, I think so. You could also do like resize factor, right? You could do this.
You could do this. Uh but let's do this for now. Old width, new width.
And So now we know that like old height or maybe we'll say in and out.
Uh the in height is content buff len over in width over four. Okay.
Out height is uh out height is or I guess it's like out len is content buff len over times outwidth over inwidth I think.
I think that's right.
Yeah. Yeah. Uh out height is out len over out width over four.
Yeah, sure.
Um now what? We need to use these in some way, right? So I guess we like iterate the output pixels.
uh out height and then we iterate the you know the width as well.
And if we were to just do like the stupid thing and sample, then we can just do like out. We have like out x out of out width.
Uh, hold on, hold on, hold on. I need to draw. My brain isn't getting there. Uh so we are like in small picture we're like here and so in big picture we need to be like here. So we have uh in width out width. So we want like the ratio of distance that we are in here in this right. So if we do like um x over out width that gives us a ratio times in width gives us the the position in in space and then we just need to like rearrange this so that we don't get [ __ ] by uh integer math. So we just do the times first.
Yeah. uh in X and then in Y is the same here.
Okay. Pipe.
Um and then we need to do something with this, right? And if we're just like doing like the stupid thing and we're just like discarding all the pixels around, we're just like we'll look at that exact pixel. Um right. So like instead of doing something like intelligent like trying to average this space that takes up the new pixel size and like put that here, we're just like ah we'll just like pick the one in the middle, right? Whatever pixel happens to be right here, that's the one that we'll use.
Um so we should be able to be like content buff.
It's like a me copy of four bytes aliasing. to go crazy. Yeah, for sure.
Uh we can maybe improve that later, maybe.
Uh so what the [ __ ] are we doing?
It's like, is it easier to reinterpret this stuff as unit 32s? Probably, right?
Almost certainly.
Uh, how do I do this? Can I just do like a pointer cast?
Uh, bites as slice, I guess, is what I want.
Resize buff picks is like this.
And then why didn't like this?
Oh, can I specify alignment of this guy then? Can I force it?
Alec with options.
So, LM size optional alignment optional sentinel. So, here can we do four like this?
Okay.
Then can we do this is like a line four like this.
Does that kind of fix this?
Yeah. Now the resize buff is mad which we can do the same thing here like this. Okay.
Now he's just mad about unused local content. Hype pi pi pi pi pipe. Uh so also we have to actually uh make this thing.
So this actually has to be like uh you know Wism allocator free the resize buff and then can we Alec this?
Yeah. Yeah. Yeah. So it's like uh let's work in pixels units now.
So no over fours anymore.
Okay. And we have resize buff is equal to an allocation of the right size. Yes.
Yeah.
Yeah.
Outland huge uh catch unreachable. [ __ ] it.
What does he like? Uh probably this going to be Alec with options cuz we No, this can just be U32.
This can just be U32. There's no reason for this to be a U8 buffer.
Cool.
Uh, okay.
So, this needs to be like a pointer cast here.
Okay, we're getting very close. So, if we're just sampling now, it's just like resize buff at in Y time uh times in width plus in X.
Uh, this is all out.
Content buff pixels.
Resize buff at out Y* out width plus out X equals this.
Yeah, pipe. That might work.
That's like a nonzero chance that we would get something sane.
Let's see what happens.
So here in JavaScript land I guess we need to call the right functions right.
So it's now do resize. So we upload this data and we call do resize.
Uh unreachable executed. Nice. That makes sense. So can we log at the very least on those unreachables and see what's what's mad.
Uh, so print internal failed to alloc this many bytes.
Not that one.
Oh, wait. I guess we have to build, huh?
Where is the other unreachables? I guess they could be in like indexing.
So, can we do like a if false here just to like double check that we're not like [ __ ] up something mega big there?
Unreachable executed. Okay.
Um, it would great be great to have a panic handler. Uh, do resize these uh parameters. True. Seems likely that's it, huh? So the input width is going to be eight uh 800 and the output width is going to be like 200. Let's do like a 4x down sample. Nice. Good eye. So that's probably in division here. I would love to get a panic handler here though just so we can like see what the [ __ ] is going on. Um, so I think you do like is it like this, you know?
Is there a panic handler in here? No. Uh, zig set panic handler.
There's like pub function panic. That sounds familiar.
Uh, zigg panic handler. Is there a way?
Uh, okay. So, panic invokes the panic handler function. By default, this calls the public panic function exposed in the root source file or if there is not one specified this thing. Hi. Okay.
So, we need to look at the builtin. I guess if we do like pub function panic, he's going to get mad at us probably about the signature and we can just copy paste it. Yeah.
Uh so it's message error return trace.
Uh I guess we should just look at uh just look at the built-in panic function was it in stood builtin or builtin?
stood built in. So we just don't go there.
Okay.
Uh here.
No, dude. Where is the [ __ ] Oh, here maybe.
Message is this ra is a u size. Okay.
Yeah. Yeah. I see. I see. I see. I found it. I found it. It's message a uh stack trace which is like like this I think. Yep.
And then a return address is a optional use size. And then so can we just do like this? And can we just do like a quick little do like print internal of the message at the very least?
At the very least. So that if we call this thing, we go back to calling this thing incorrectly.
Can we at least see a little failure, you know? So it was like this. We should see like a divide by zero or something.
uh expected this it's a pointer uh error union is ignored does thing return uh no return true so here there if I type unreachable again here I think it like recurses into our panic handler which isn't good But we'll see. We'll see.
Yeah. See, we're like recursing now, which is really bad. Um, so we need to do like I think it's Wom.
There's like some sort of like wom panic built in I think that we can call instead there like to to just go straight to like the I can't remember.
I can't remember. There's something about that trap builtin. That sounds right. That sounds right.
This function inserts a platform specific trap jam. Yeah. Yeah. Yeah.
Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. So, this goes dodges the rest of the panic handler, I think.
What books do I read to get to the same level as you? Oh, I don't really read.
So, unfortunately, I can't really help you there. I just do things and then like draw off previous experience.
That's kind of the way this usually goes.
division by zero, baby. Let's [ __ ] go.
And then you can probably be like, um, if stack trace, I think you can just like [ __ ] log that [ __ ] No.
Uh, empty string.
Uh, how do I log these things? I feel like I've done this before. Format.
Yeah. So, he has a formatter and then I guess uh has, you know, with stack trace.
Maybe it's just like not available to us. Yeah, looks like looks like we can't we're not that we're not that fancy.
Maybe there's a way to get it, but it's at the very least not trivial.
Not trivial. Okay, so now we can go back to actually doing the resize and see if it actually works. Uh, unreachable executed division by zero because we didn't actually fix.
We We do want to do this.
Okay. So then, you know, maybe it worked. There's like a non-zero chance.
Non-zero chance. It's hard to tell right now because we're just like logging like the big yellow [ __ ] So, I think what we want to do is we want to do this on the file upload, you know, like I think it's like on load we want to draw the image then do all this [ __ ] you know, and then maybe draw it back.
Uh, so can we like kind of do this?
Where is image data get used? Probably here, right?
Probably.
Probably.
Then all of this can kind of go here after the WM object is initialized. So now we refresh and we upload our little picture. So that's in here now. And then what would be nice is if we could like print the resize stuff into like a second canvas, right? So if we were to go like or maybe we just p punch it in the same canvas.
[ __ ] it, you know.
Uh so let's let's get the new buffer. So we'll say that we get like resize len is image wom instance exports whatever the [ __ ] we called our thing which I don't remember.
Wom test it was get resize buff and get resize when so we have resize pointer and we should be able to like look at this stuff by doing like something like this uh resize pointer resize len and can we just like look at this thing Like what the [ __ ] in here?
Hello. Resize pointer. I spelled that wrong. So we upload our file and we do see what we should see is like a picture in the top left kind of followed by like a [ __ ] ton of yellow. So if we go into like the kind of like end segment, we do see some yellow down here. Yellow, yellow, yellow, yellow. That's good. Um, what do we expect the length to be? We expect the length to be 200 by 200 * 4, right?
200 by 200. Uh, no, cuz the aspect ratio of this thing is not 1 one.
So, it's like what is like the dimensions of Oh, it's Oh, no. This is one. This is 800 by 800 pixel buffer that we're sending in. So it's yeah 200 * hello hello 200 * 200 * 4. We're looking for 160,000 which we do see here. That's really good. That's really promising. So can we convert this thing back into an image?
like can I do like uh yeah let's just draw it on top.
So we'll do draw image. So I guess we need like new can we do like a JavaScript draw pixel buffer canvas or something?
Is that like a thing we could do?
Um write an array buffer canvas. That's what I want.
uh image data from this uh so we want from resize buff 200 200 uh resized is this and then we can do ctx draw image resized at like let's draw it in the bottom right okay so we load this guy uh argument one does not implement interface uate clamped array. Oh, so do we have to do like can I make a clamped array from a date array?
Uh can I just like do this instead? Does that do the same [ __ ] thing?
Uh argument one could not be converted to any of these from testJS 53.
What the [ __ ] This guy's a liar.
Oh, put image data. I didn't read.
I can't read. It's a hard life out here.
I always say reading is for [ __ ] nerds.
Okay, that's close.
That's really close. So, I think that what we've seen here is that we just didn't resize height correctly.
That seems likely, right? So, it looks like we've kind of clamped the width down, but not the height.
Um, so let's look at that. Resize buff out y time in in y is out y * in height over out height.
So it must be that our out height is just wrong here.
No.
Uh outland over out is this over four content buff pixels.
Uh print internal uh output size is going to be this by this.
Like what the [ __ ] are we doing wrong here? Out width out height.
Should we out y times out height?
No, because we're going like we have like n rows of stuff, right? So if you're going like if you're trying to like index into this pixel buffer that's going like this, it's like your offset is like this many rows of width, right?
So that doesn't feel like it. It feels like the units are all right here. I'm more interested to see Yeah, maybe we [ __ ] up.
Uh on Oh, okay.
Uh 200 by 800. Yeah, we're just [ __ ] idiots. Why is this wrong?
Why is this wrong?
Oh, Len is What the [ __ ] dude? Am I mental out length?
Hold on. Hold on.
I'm sure it's like really obvious, but I'm not seeing it. So, our outlength is 200 by 200 by 4.
Oh, wait. But this is the wrong unit.
This is in uh this this is in this is in pixels, not bytes.
So, how the [ __ ] did we manage to [ __ ] that up?
I'm lost.
Outlet is only calculated using the width modifier. No.
Well, we have like the total length of the input buffer times the ratio, the resize ratio, right? This resize ratio is supposed to be applied in both width and height.
But I mean, we could just do like width over in width, right? Like this is kind of what we're trying to do here.
And then maybe we do this instead. We do like out width times out height, right? That's like maybe more correct.
And then here we need to make sure that we do like over four here for the resize length.
Okay, let's see if that kind of does more what I expect.
Uh, output size 200 by 200, which is 40,000 pixels. And then index or size is negative or greater than the allowed amount at test.js 52 uh test.js 52. So that's here.
So, we logged the resize buffer here, which is only 10,000 buff bytes. Probably because here it was supposed to be times four, not over four, right? Cuz we're going from 32 to 8.
Oopsies, wrong file.
Okay, that looks promising.
That looks like we kind of have like a small version in the bottom right.
that I'm pretty sure that's right.
Pretty sure that's kind of cool.
So, we have pixel data here. And now the last piece is trying to do the the like file conversion from within WM land instead of relying on the canvas to do it.
Uh, ideally we completely ditch the canvas.
Boo canvas. Let's get that [ __ ] out of here. So, uh, one option. So, two-step suggested zig image.
Um, usually I'm a little hesitant to just pull in libraries, but [ __ ] it, you know? I'm down.
Um, so I assume we do. How do you build Ziggs on again?
build Zigg on.
Uh, I guess I kind of just want this.
Uh, I guess we can kind of just like touch build Ziggs on and see where it gets angry. Nowhere.
Oh, we already have one. That's why. U, okay. Dependencies.
Oh, we already have one. We've we've we've been here before, right? So, can we look at um Zig image?
We did write a PNG decoder by hand ourselves at one time, but I'm not willing to go through the work of like making sure it's correct.
Um, dependencies. Oh, yeah. There is just like a Zigg thing to do that, is there not? Huh?
Uh, so you're saying I can do like copy here. You're saying I can do zigg fetch save get plus this or something.
Oh, that's kind of cool.
That's cool indeed.
Okay. So here if we're like uh b dependency zig image.
Uh okay. And then like what the [ __ ] does this thing export?
We have a module zigg image.
Zig image is this. And then we say like wom AC add module uh root module add import. Yeah.
Okay.
So he's going to do some [ __ ] Uh dependency. We need options here.
Probably just like I don't give a [ __ ] We might like it might be correct to propagate target and optimize.
Uh but he seems happy for now.
Wom test. So, can we do like zigg image is equal to import zig image? That'd be kind of cool. Looks like it. And how the [ __ ] do I use this thing?
Image. Surely.
Uh, in it with an opator from file from memory, right? Like this. Like this. And then we have like from raw pixels as well, but we can probably just do from memory.
Does this thing are they gonna cheat? Do they have resize in here for me? I hope not. Looks like no.
Cool.
Wow, they got all sorts of stuff in here. Okay, cool.
Uh let's go back over here wherever our like wom test is. And can we do like um zig image image from memory with stood keep wom allocator and content buff.
And then we should be able to be like this probably can fail, right?
And let's just kind of go here.
Um I'm I'm hoping like what is like the pixel format here? Uh can we like ask him for a specific pixel format?
Let's see.
read image.
So, this gives me like a format interface.
Oh, that's fancy.
Uh, fancy. So, he goes all for each interface function. Wow, that's cool.
That's some [ __ ] dude.
Uh, okay.
Let's see if they have some form of like it feels like um pixel format converter. Here we go.
So we can convert this to some desired pixel format.
Okay.
So this is in pixel format converter.
Right. So we should be able to be like uh zig image pixel format converter convert from image pixel pixels.
This guy wants a pointer to pixel storage. This guy is not a function. I see. So we can kind of go like this into like RG BA32.
Right.
Nice.
Um maybe not unreachable because it might just fail as you code. Yeah, true.
But I mean the the crash will just the unreachable is kind of like an exception. which is kind of funny, right? Because like it'll just bubble up to like the Wom boundary.
Um, quick question. Do you use WM in HTML?
If yes, how do you pass the image WM side? Is it like a big clone of the JS buffer or your pointer placing some we're we have memory in zig wom allocated memory exported by zig. And so we have a function here that says please create a buffer of this size and then we will copy in from JavaScript whatever we need. You do your stuff and then we copy out.
Um, I think there's a way to like load data directly into the Wisom buffer, but it's fine, right? I I think that I've done this before where like you do like bat you do like 4K chunk fetches of like whatever resource you're fetching and then like inject that directly into like the Womland or whatever. But this is probably fun for now. Uh, can we So, if we have this thing now, what does this return? Pixel storage. And if we pixel storage, we can just take out the RGBA 32 here and probably just do like a pointer cast on this thing to get the same thing we were doing before.
Uh, so we should be able to be like image 32.
Uh, catch unreachable.
Uh, RGBA32.
Uh, can we do like pointer cast?
I don't know like how much he'll like this, but we'll see.
We will see. Okay. Uh, increases point alignment.
a line cast.
[ __ ] it.
Uh, okay. So, this thing's pissed that uh we are trying to compile Zigg image and he's trying to use some Pix [ __ ] That's like a pretty reasonable expectation of this guy, right? So, we would need to like fork this guy.
uh or something. So this is kind of happening in formats SGI, right?
So we're seeing seek at 153.
So he's like doing some sort of like seek from stream.
Yeah.
Um, okay. So, he does have this.
So what's Wait, why is this freaking out then?
So he thinks that we're going into like pix mode here for some reason at SGI zigg 153. Oh, target. I probably need to pass the target along. No.
Uh, no, because it's it's like a module.
H it looks like it is supposed to handle this.
Oh, this is Yeah, this is a stream source in the Zigg standard library.
Yeah, which should be fine. No, this is Zick, which makes me think that the target isn't being set correctly, but it has to be.
Maybe I [ __ ] up WM32 freestanding in my build, Zigg.
It does say freestanding here, so I don't really see how it could be wrong.
[Music] But it does seem to think it's using the PZIX version, right? It says here.
Oh.
Oh, wait. There's also this. Oh, these are two different things.
Oh, these are two different things. Hold on. Hold on. Hold on. Hold on. So this is he's trying to do system write on standard error unsupported operating system free standing on thread.
Yeah. Okay. So it's not that easy. It's unfortunately uh not that easy. So, I think that I'm I'm more likely to find success at this point trying to get STB image to compile correctly. And I just think that's like not a very interesting thing to be doing um at the very least in the YouTube segment. So, I might take a run at that after this. Uh, but for now, I think I'm happy to kind of call this segment of the stream here. So, what do like, you know, we did like the world's most naive resize in Web Assembly land. So, what do we do? We have like our WOM test. This guy has uh some functions to like uh manage memory from JavaScript land to say, "Hey, here's a content buffer. Let me know when you've got some stuff in there and we'll do a resize from this width to that width. All we do here is like the world's simplest resize. We just sample the existing buffer and then copy paste it down. Um and then we say okay here's like the stuff that we uh here's the stuff that we resized and then in JavaScript land we just instantiate the web assembly module. We use the canvas to turn uh image data into pixel data, ask for a resize, and then render it back to the canvas. Seems like it was working. Um, pretty exciting stuff. So, yeah, I think we call it there. Uh, Twitch, stick around. I think we're going to keep going on some other stuff.
Um, but YouTube, if you like we saw, we stream most days 12:30 Pacific time to 4:30 Pacific time. It is two I guess the live people it's 2:15 now. So two hours ago to two hours from now is approximately when we're live. Um if you want to keep up with the projects we're working on swing by catch us swing by if we're if you're around um on Twitch but also uh you know some segment of the stuff ends up on this YouTube channel.
Um, some segments don't, right? Because basically we're like at the whims of the uh of the algorithm. And so the stuff that goes on this channel is stuff that we hope um is clickable, right? But we do a lot of streaming here that's not necessarily in that category. And so that stuff gets posted on Patreon or under YouTube members or um in Twitch VODs where you pay in the appropriate places to get access to that stuff. Um, you know, we do that because it's an excuse to uh give something to people who want to support the stream. The stream will die uh when I run out of money and so it's like a way for, you know, to slow that death. Um, so if you want the stream to continue, please consider supporting in those places. But if not, no sweat. Um, I think that's it.
YouTube, peace out. and Twitch. Let's uh let's pivot.
Up Next

Sound Synthesizer Oscillators and Envelopes Programming Tutorial
@javidx9
80.8K views•2017-02-27

IFS Therapy Demonstration: Complete Session with Unburdening
@IFSCA
95.9K views•2021-01-13

FastAPI vs Flask vs Django: Choosing the Right Python Web Framework
@TechWithTim
302.5K views•2024-05-26

Game of Thrones Opening Credits: A Cinematic Analysis
@gameofthrones
46.3M views•2011-04-18
Related Study Plans & Knowledge Roadmaps
Structured learning paths in General & Interdisciplinary Studies






































