 Hello, folks. Let's talk about colors and the prototyping that I've been doing in that area. If you remember from the, I think it was the first entry? Yeah, probably. The one where I was talking about the icons, which I've got on screen, you can see. Do you remember how I was saying the color scheme of the site was going to adapt to the content? Well, if you remember that, and I mentioned, I think, at the time that I was using a thing called medium cut. And I thought I'd show you a little bit more around that in this particular entry. So what I have is I've just I've got a script here, which is it's all JavaScript written in Node, which I would expect to ultimately be part of the build process so that when I take a video in and it's thumbnail image, I can pass it through to this script and say, what colors do I need to have for this video? And it will spit me out a palette of 16 colors. Let me show you it running there on the screen there. Node, swatch test. And then I've got this image here that I took of Gibraltar when I was there. It's a very nice place to go and visit. It's quite small, though. It's not, I think it's like a mile long or something. I really enjoyed it. Anyway, nonetheless, we have the photo of that. And we'll run this. And you can see it says quantizing to 16 buckets. So what it's doing is it's trying to find the 16 representative colors from the image. And it spits out a bunch of RGB values. But I've also had it make an HTML file, which if I double click, looks like this. And so this is the palette of 16 colors that it's derived from the photo, which if I put the photo up, you can see that those colors look correct. So how does it do it? Well, median cut is the answer. But let me show you around the code. So the swatch test, it loads the image that I whatever I give it. And then it gets the pixels back for the image. And it asks the swatch class, which I'll step into in a moment, to quantize. Quantize is basically grouping in this instance. And then it orders them by luminance because you've got to order the colors by something and sort of brightness, luminance is pretty much one of the best ways to do that because it means you know that it's going to kind of get brighter as the palette goes along. Anyway, we'll come back to that in a little bit. And then you see I write that out. And then I write this file just so that I could show you basically what's in the swatch. So how do we do a swatch? How do we create those images? Well, loading is just a case of loading the image. And I am using GetPixels here, which is a node module that kind of behaves similarly to the canvas, that you can draw in an image into the canvas. And then you can say, get image data on the canvas. And it will give you back a contiguous array of pixel data, which means that rather than having, say, an array of objects with RGBA, you just get one long array with RGBA, RGBA. And so you have to step up in groups of four and pull the red, green, blue, alpha values per pixel as like a block. Anyway, so you can see actually what I do is I call GetPixels, which does a similar thing. It gives you back one of these contiguous arrays. And I convert these across to RGBA, well actually RGB in this particular instance because I don't need the alpha values. You can see that it's pretty much what I was explaining there. You go up in, well, I go up in x, y values. So I go up in each row. And I times it by four because I know that each one of those pixels will have four items in the array. So I pull those out. So we end up with an array of objects which I have R, G, and B values in. So that's one per pixel of the image. Great. The next thing to do is actually do this median cut stuff. And if you look at the Wikipedia article on median cut, it's actually really good as an explanation. It explains that what you do is you find across all of your pixels which component, the red, the green, or the blue, has the most variants in it, which ones have the largest range of values. And you use that one, that component, the red, green, the blue, as the one to order all the pixels by. So you'll say, for example, you go through that process and you go, ah, blue is the one with the most variants. And what you do is you order them all the pixels by blue, their blue component value. And then you split the whole array in two. So now you've got two buckets. And you repeat that process to the end with four, and then eight, and then 16, and so on, and so on, and so on. And the idea is that eventually you'll reach the base case of this recursive process. And you'll say, right, I've got a bucket with however many pixels in, and you average that whole bucket. Now, at each step of that recursive process, you could say, need to order by red or green or blue. So you'll always run the process that gets you the one with the biggest range. So if you see here, I've got this find the biggest range, and it just takes a bunch of pixels. And you can see I step through each pixel in there, and I figure out the, oh, that's wrong. That should be max, max, max, max. Oh, fixing bugs on the fly, eh? We'll have to run that again, see if that actually fixes anything. That's what you get, Paul, when you copy paste. Just as well, it's a prototype, isn't it? So anyway, we go through that process, and we figure out the max in the min, and then we figure out where the red, green, or blue has the biggest range, and then we basically return red, green, or blue, depending on which one has the biggest range. That shouldn't have a semicolon either. There we go. Next up, we have the quantizing. So imagine now that we've ordered our array, however big that is, of pixels by red, green, or blue, and we now need to bucket them appropriately. So we will do, let's do the recursive case first. So we start off with a big array, say, I don't know, 1,000 pixels in there, whatever, and we figure out which one of the components, the R, G, or the B, that we want to sort by. So we then sort all our pixels by that. And then what we do is we slice, hence the name median, slice it down the middle. And there we basically quantize. We call down into the same function, again recursively, with the left half of the sorted array and the right half of the sorted array. And we increment the depth value by 1, and we still maintain what our max depth is. Now, I'm going for 16, which is 2 to the power of 4. So you'll see that my max depth is defaulting to whatever this default depth is, which at the top, you'll see is 4. So we go, so 1 would be to 2 buckets, 2 would be to 4, 3 would be to 8, and 4 would be to 16. And that's how we get the 16 close in the bucket. And the base case. This is the base case. When we actually hit the depth equaling the max depth, we step through all the pixels in that particular bucket. And we add them all up, all their RGB values up. And then we divide by the number of values we have to get the average and round it. And we return that as an array with just a single color in. And because I've got the spread operator here, all those will then get turned back into an array of colors. And that's basically how we do it. Ordering by luminance, if you want to do that, it's very well documented on, again, Wikipedia and wherever else that says, take a pixel. And times its red component by, in this case, 0.2126, green by 0.7152, and blue by 0.0722. That will give you a scalar value or just a number, which you can then use to order. So you can see it's part of a sorting function here, where I can calculate the luminance for a given pixel. And then I just sort my values by that. And that is basically what's involved. Now, since I have actually fixed the bug, let's run it again and see what happens. So let's do that. La, la, la. OK. Do we get a vastly different swatch? We do. We do. We get a different swatch now. No, that's my fault for having a bug. But again, you can see those colors. If I bring up the image as well, you can see that those colors are still correct. It's just that I was doing a medium cut in the wrong place, essentially, by ordering by the wrong component. But you can see, now I actually get a much broader pallet. So that was good. Glad we had this chat. Good. So that's how this works. Now, the other thing you can do once you've got a color like this is you can do things like complementary colors. If you think about the HSL, if you've not done HSL, it's where you can think of it as like a color wheel going from red all the way around the rainbow back to red again. So that's the H, the hue. And you think of that in the color. I think you actually mark that between 0 and 360 degrees when you mark it in CSS. And then there's the saturation, which is obviously how saturated the color is. And lightness, taking it from white to black. And I think 50% lightness is essentially the color in the middle between black, the color, and white. If that makes sense. But what we can do is if we have a color and wherever it is on that color wheel and we spin it through 180 degrees, that will be the complementary color. So let me just show you that in DevTools very quickly. So I've picked this one here, this one here. And in DevTools, you can click on the color and you get this little thing. And it's currently set to an RGBA value. But if I do that, you can see that it's now gone into HSLA. So you can ignore the alphabet because we don't need to know. So 48 plus 180 degrees will be 228 if my maths is correct. And you see we end up with this kind of purple color. Whoops, a daisy. So that's what it was originally. In fact, let me, yeah. So I don't know how I'm going to put this side by side. But if I could, I would easily. But I don't think I can very easily. Wait, wait, wait, wait, wait, wait. Did I say 136? No. Let me just reload this page. Did I get that wrong? Oh, no, it's because it's an RGB. Dear me, I am having a bad day. HSL, there we are. So if I do 228, you can see I end up with this kind of purple color, which you see also works just fine in terms of the colors around it. But it is actually technically the complementary color. So if I pulled out that kind of light brown as this is the color I think I should use as the dominant, the primary color for this palette, then I can also find its complementary color by converting to HSL and then spinning it through 180 degrees. There is plenty of code out there to show how you convert from RGB over to HSL. So I'm not going to get into any of that. And also I think you probably can do it in SAS. I imagine there'll be sort of SAS helpers that let you do that, maybe not. But all the same, there is plenty of code. So I'm not going to go into that. But there you go. That is how I intend to get from a thumbnail of a video and find out its colors and then figure out what swatch I need. Eh, brilliant. All right, I will catch you in the next one. I think what we'll do in the next one, the next entry is talk about Shaka Player, which is how I think I'm going to do all the dash and HLS video playback stuff. See you there. Hey folks, thanks for watching. Don't forget that there is more content that you can find kind of over here-ish. And if you want to subscribe, there's probably a button, I don't know, maybe there, maybe somewhere around there. Click that if you've not done that. Brilliant.