skip to content

Better Images in Next.js with Cloudinary

Cloudinary provides powerful transformation APIs so you don’t have to waste time fiddling with images. Colby Fayock has a new library for Next.js to make it even easier.

Full Transcript

Click to toggle the visibility of the transcript

Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.

JASON: Hello everyone and welcome to another episode of Learn With Jason. It was a race. You see how it showing the wrong thing. This is not Brian. This is in fact Colby Fayock. What's up, Colby? How are you doing?

COLBY: I am good. How about yourself?

JASON: Just slightly panicking.

COLBY: Everything is fine.

JASON: No, I realized like 5 minutes before we went live I had broken my website which is the API that powers the overlay so I had to fix the website so the API work so the overlay show the right thing. Race to the finish. We got there. It is so good to have you on the show, Colby. This is your first time on the show, right? For folks not familiar, want to give us a background?

COLBY: I am Colby Fayock and I am a developer experience at Cloudinary. I do code, content creation, similar stuff to what you do but for Cloudinary. That's me in a bubble.

JASON: Today we are going to dig into Cloudinary and it is a big tool in my tool belt. I use it for everything. The placeholder image that shows up when the screen starts is automatically generated by Cloudinary. Those are Cloudinary images. If you go to any episode of my show on learnwithjason.dev and add/poster.jpg it will use Cloudinary to generate an image. All of this is stuff I have to very carefully automate because there is no way I have time do this. I always want custom something and stick someone's face on or show the current author or something to make this feel personalized so it isn't me copy and pasting the same default image every time I share a link. I have just found Cloudinary helps me solve this huge category of problems very quickly and I am pretty sure I am still on the free tier. It is a massively powerful tool with a really generous free tier. And yeah. I got paid to say none of that.

COLBY: We will send the swag to your house. [Laughter]

JASON: Colby, tell me, like, you know, obviously I am very familiar with Cloudinary and loving it a lot. But for folks just learning about it or have only used it in one or two application, want to give the high level what it?

COLBY: We are everything from asset management to delivery. From asset management it can range from the develop oriented stuff like uploading pragmatically or work with creator where imagine you want one source image from the creative team and from there you can programmatically do a ton of stuff with that image such as crop it dynamically or responsive images comes in very helpful and transformation like background removal and color replacement. A lot of interesting things. I think Tech Crunch coined it as a Photoshop API or something like that because you are basically able to programmatically do Photoshop-like things. Like your cards -- that's something you can do with the codebased API that might find someone do in Photoshop or nowadays might be Figma or something like that.

JASON: That's what I was doing before. This is a very real use case that illustrates your point. So the way Learn With Jason worked before is the only way I can run the show is I have an administrative assistant and scheduling and putting stuff on YouTube and learnwithjason.dev and without that my world would crumble. I used to have a Figma template and I had setup symbols in Figma where there was this is the guest image and this is the text and this is the thing so go in and put the guest image in this box and type the title of the episode in this box and date in this box and I would update a bunch of composed place holders for the schedule, for the coming soon, there was like a scheduled image, a starting soon image, and like a this has already happened and this is the poster for the reply image as well as guest thumbnail with a name below it and a bunch of things I needed to exist. My system would have to go into Figma and manually drop these thing ins and also go into sanity for the CMS I use for Learn With Jason and go in and upload it there. It was a lot of content entry and opportunities for things to get wrong because I would notice this isn't somebody who is in tech. This is somebody who took an administrative assistant job so the wrong person's face showed up in an image and they don't know better because they never met these folks or they would not know how to spell a framework that has interesting spelling so you would see a missed capitalization of WordPress or something so I would have to go in and fix it. It was just labor. Then when I figured out I would solve this with Cloudinary, I took my template out of Figma and put it in Cloudinary as a blank template and uploaded custom fonts and hooked it up to the sanity API is so now y I have a serverless function calling the API with the episode title and guest head shot and shows the right date and puts the guest name on and uses the URL of their thumbnail to put a layer in underneath the template. It was all like a lot of layers so it took me a while to get it setup but once I got it setup I have never had to touch it since. As it probably cut 30 minutes a day out of my EA's workflow.

COLBY: And I would imagine that includes different sizes and stuff, too. Not just of the same image. But you probably have different formats depending on where that image is being used. Being able to have that. Imagine cloning all those different ones and now you can do that all programmatically from the data source.

JASON: It is such a game changer to figure out. Especially as I like to do design and they don't have the time to dive in and really get after this. Being able to get a design that I like once and then I am not in Figma where I have temptation to tweak it and I have wasted two hours staying up late finishing the work I am supposed to do. I feel like that automation when you have these tasks that are simple and don't take that much time but they have a lot of temptation or just have a lot of wiggle room for human error. That stuff is so important to automate out of the way because the way I do my thumbnails changes once a year. I don't re-brand Learn With Jason that often so the thumbnails I am using now are two years old and I am starting to entertain the idea of doing another one. When I make the change, I am going to automatically re-brand every other episode I recorded because it is just from the Figma template. So I will update and all the images update with the right information because it is programmatically generated. That's huge.

COLBY: That's a lot of time. That's fantastic. It is amazing how this is a one single use case that's already saved you so much time compared to all of the other things you are doing on the web.

JASON: Exactly. It really is just kind of a -- I feel like Cloudinary is one of those services, there is a category of services that I have started to think of as like the great equalizers where it allows somebody who is a team of one to do things that are competitive with massive teams. And so you know Cloudinary is one of them because all I just described. I think of serverless functions like Netlify as another one because I don't have to stand up a server and I don't have to figure out how to write express boilerplate. I write business logic and I am off to the race get push to deploy. There is a suite of services I heavily rely on and they have helped me automate so many things I have started thinking of and I have been saying this and wondering if it is too dismissive but what I call undifferentiateated labor. What I mean by that is when I do the work to copy/paste the title and guest image into the a thumbnail that is not -- I am not generating value. I am following a process. I generated the value when I decided thumbnails would look like this and communicate this information. Doing it manually over time is wrote process -- copy/paste, copy/paste, save. That is undifferentiated. It is not adding value or making anything better. It is just time. The same with like if I have to go copy/paste the broiler plate for an express server every time I want to do logic that is just time. Your express server doesn't get better or worse because it is written by hand. It just a router. I need a request to go in and a serverless function let's me do that with no DevOps or broiler plate and that undifferentiated part. The thing that is the same for every project disappears.

COLBY: I felt the same exact way with Netlify. Not to just throwback the love. We had Jenkins for everything with all the AWS cloud formation and the first time I deployed a site on Netlify I was like I can do all this stuff that is not unique to me super eel easily and get my stuff on the web. It is removing the stuff that is not unique so we can be more unique.

JASON: The goal of this is we have a business because we think we can make something valuable and the time should be spent on building the value and not on the scaffolding that allows that. Whenever I find a tool that removes broiler plate, I spend on a given day when I get to do engineering work which isn't many days, but when I do engineering work, the vast majority of tie my time is spent on building the value of the idea now. You can get the concept out of my head like my broilerplate, I deployed hello, world in about three minutes. You create a folder, hook it up to GIT and you are deployed.

COLBY: It is an exciting time to be a developer in this space because of all these tools we have.

JASON: Absolutely. Speaking of tools and how nice it is to be live, you have built something. As a little bit of context setting here. Cloudinary has an URL based API that I love and also has a node SDK which is a JavaScript based object config driven API. A lot of people are using Cloudinary to power a lot of different sites. We are seeing Next.js emerge as one of the leading frameworks if you are building complex dashboard style or app style apps. You have built something if I understand correctly it is a Next.js library for using the Cloudinary SDK? Is that right?

COLBY: Yeah, so what I was attempting to do is I didn't want to reinvent the wheel that was aural already existing because Next.js did a fantastic job with the image component. Thinking before Next.js 13 we had a Cloudinary loader. It was basic and it had a few things but didn't do a ton of things that Cloudinary can do like over lays. After Next.js 13 they don't have that cloud loader built in. You have to attach them to every single instance of the image tag so there is a lot of complicated pieces there. I didn't know that specific change was coming so it set myself up well for this. What I am doing is taking that core image component that works really well, I am wrapping it with a custom loader that also extends it with more Cloudinary features. One example of that is you can use the sizes prop the same as you would with the image tag but it uses Cloudinary URLs but extending that now you can add a remove background prop and that will remove the background from the image using on the fly processing. It is able to have that core amazingness but just take it way beyond with all of the Cloudinary features that we know and love.

JASON: That's great. That's really great. I think what we probably want to do here is is there any sort of abstract or sort of like philosophical underpinning of this that we haven't talked about before we jump right into the code?

COLBY: I guess really the only thing I was trying to do was make the props API a little bit more intuitive. The Cloudinary SDK is and APIs can do a lot of awesome things but they are very specific. I can very finally tune all the different attributes of an image but I want to make it a little more intuitive so you basically express what you want and then have that ability. I think that's really the only thing. I would like to also abstract this and put it in other frameworks but my first release it was Next.js.

JASON: Gotcha. I think I have found I always want to bring Cloudinary in for my sites because there are a few things I have to do every single time that I hate doing. When I write a blog post I know I am going to put a screenshot in there and that's probably going to be a PNG because that's what Mac does by default and I know it won't be optimized because if I don't take it to something like tiny png I am getting whatever the Mac gives me.

COLBY: More manual labor.

JASON:. These little things you have to do every time. I am using Edge and a lot are using Chrome and can handle modern formats way smaller than a PNG. I know if I am doing my job right I added a source set so on my iPhone I am getting an image of the appropriate resolution for the iPhone and on my desktop I am getting the full resolution screenshot with all of the details so I am not wasting bandwidth and I don't want the bandwidth charges. If you have an animated GIF that is 8 megabytes it staggering how quickly you burn you bandwidth.

COLBY: You are saving yourself money by optimizing into that.

JASON: You want to keep stuff on the free tier find ways to shave off bytes and bandwidth. Companies charge for usage usually so use less. Whatever it is I am building I am going to try to find a way to get Cloudinary to automatically send the right format of image and send the source set of the 5 sizes I want to send for different resolutions because I don't ever want to manually create a source set or and honestly, I understand in the abstract how content type negotiation works. I don't think I could build it. I have no idea exactly what I would do to get a request for a PNG but send back a web P if the browser supported it. I know the browsers let the request know I accept these and we can do middleware and that's what Cloudinary magic is doing but I don't want to build that. That sounds terrible. Given the option of like if I can't use Cloudinary, I just don't do that thing which means I am using more bandwidth, I am wasting my user's bandwidth when they load it on the phone and get the full size PNG instead of the optimized version. It is just bad for everybody. There are a lot of things I really like about Next.js. One of them that I actually kind of struggle with is the image component because I've found it to be prescriptive to the point of being kind of hard to use.

COLBY: OK.

JASON: When I want to plug it into Cloudinary because I don't want every image call to be running through like that's bandwidth and a lot of processing and bandwidth we are using to like process these images on the fly. I want it to be done through Cloudinary because I know when Cloudinary does it, I have the proof, it is optimized once and served from the cache and that means by bandwidth use is way lower and I know Cloudinary is optimized for asset serving so the free tier is designed to handle that bandwidth. The idea of having something that automates this. I haven't tried it on next 13. I didn't realize they removed the Cloudinary plugin. What a bummer. That tripped me up too. You would start using image and you would do the Cloudinary thing and it would break and you are in the config trying to remember how to turn that on.

COLBY: It was always a little confusing to use it as well especially having the different options. Now you can technically white list or add to the list the URL. You are not really gaining those benefits ultimately. It is still going through the Next.js pipeline.

JASON: Exactly that. I felt like I was giving up one of the strongest tools in my belt and getting locked into this thing that at the end of the day it does feel like a lot of Next features are being designed to drive you to a single platform that they want you to pay them. And cool. That's fine. Business models are business models but I don't want to do that. I have my tools. I want to use the tools that I like. So I am very excited to see quat -- what you are building and that might be a good excuse to flip over and look at some code. Let me close a couple things because I was doing the panic of fixing my website. We will switch over into pair programming view. Here we are. I need to reload this one as well because it has the old scene in it. There it is. That's the right thing. And I am going to start us off by doing a quick shout-out to our captioning. We have Maggie with us today doing the live captioning. That is on learnwithjason.dev and you can find those captions there on this episode and every episode. I actually got a hint that I might be able to embed these directly into Twitch so that the closed caption button works and I haven't had time to explore it yet. Twe, thank you for helping me dig into that and how it works. Maggie is here with White Coat Captioning. If you are doing an event, you can always get White Coat Captioning. They are the best. That's made possible through the support of our sponsors, Netlify, New Relic, NX all kicking in to make this show more accessible to more people which I appreciate so much. We are talking today to Colby Fayock and you can find Colby on Twitter possibly for a limited time. [Laughter]

COLBY: I think I followed you and Sarah on there and I literally that was my first real -- on Masadon. We will see where that goes.

JASON: I am trying with Mastadon. I do like it. I am trying to use it. We will see how that all shakes out. We are talking about Cloudinary today. This is the Cloudinary site. Dropped in the chat. You can check it out. We are going to skip over a lot of the onboarding here but there are good docs and good examples but today Colby is our docs and examples. We are also talking about Next.js so we will plug that in and see how that goes. Colby, what should I do first if I want to start setting this up?

COLBY: Do we want to go through the account first or dive into the code? The assumption is you have a Cloudinary account.

JASON: Let's go to the account. I have got my account here and let me pull it off screen because I don't know what is going to pop up when I click open. I am going to sign in with this one. I have my Cloudinary account here and I am going to login and thank you, one password. This is my -- yeah, OK. That's the public one. I was like no! [Laughter]

COLBY: Whew.

JASON: This is my Cloudinary account. I have a whole bunch of stuff going on here. You can see I use this for a whole bunch of stuff. I have tons of things in here. This is my media library that's full of things. I have tons and tons of stuff in here including all of my Learn With Jason stuff. You can see my templates here and a bunch of miscellaneous assets and once upon a time we had Ben host the show so I had an alternative thumbnail there. These are all of the things from my blog. I use it for everything. Like it is in heavy rotation in my universe here.

COLBY: I would imagine most of this stuff is being programmatically uploaded, right?

JASON: Almost all of it.

COLBY: A lot never see the media library. The media library is great. It is where you can visit photos and videos or whatever but this plays more interesting into like creatives where they are just uploading these things. You almost have that automated as we. A lot of cool things you can do inside here as well.

JASON: Absolutely. Is there anything you want to dig into specifically in here?

COLBY: We have kind of two options for how we can use the components. By default it will expect a public ID. If you look at the asset, it will be the ID at the top including the directory structure. If you are looking at the first or second one Learn With Jason OG 2002 is the public ID. It will take that as the source by default. -- 2022.

JASON: Yes, if we look at this, this is my cloud name.

COLBY: Yup. You got the cloud name, then you have asset type, then you have the delivery type which you uploaded that as opposed to our fetch API which is the other way where we can set delivery type to fetch and if you pass in an URL as the public ID, Cloudinary will fetch that from the remote URL and cache it and do everything else. It just makes it easier if you still want to control source assets. You just have a little bit more flexibility from that though you don't get some of the features like background removal. You can't use on the fly background removal. Ever so slightly. It works the same for most use-cases and it is a nice way to go about it.

JASON: Then we have this version which is optional. You can leave that out. And the folder I put it and the name of the thing and the content type.

COLBY: The content type is actually optional as well.

JASON: No, it is?

COLBY: That gets stripped along with the public ID.

JASON: Cool. OK. All right.

COLBY: I guess we can dissect the image format. What you are looking at in the URL is the API. The URL is the API. What the SDKs are doing is the same thing where we are constructing that URL and adding parameters for transformations or optimizations we want to do. You can literally build your own API with just an URL FOAF -- if you want. We recommend the SDKs but if you wanted to shop chop up an URL and serve it you could.

JASON: I do a lot of transformations and do them over and over. I will show you the one I do all of the time. People ask me for a head shot because I am going to speak at something. So I come here and I have this image that I -- this is full sized but this image is huge because I don't know if people are going to do a brochure so I want them to have access to a bigger version but this is absurd to send to somebody but they want a head shot. They want this section not the full image and I don't want them to have to do that on their own so I do a couple things. I start out doing Q auto and that automatically sets the quality. We should look at this in the network because I feel like this makes such a big network. If we do this, this is a 5 megabyte image we are delivering right now. It is a JPEG. Then the first thing that I do where've I have an image is add Q and F underscore auto. Q is quality and F is format. A couple good things happen when you hit that button.

COLBY: So the first time -- it as a pretty big image so the first time it might take an extra second to process it on the fly but it is cacheed and then if you refresh it will happen fast.

JASON: This is now 2.3 megabytes so less than half the original size but still that big image. That part is amazing. If we look under the hood now it is a WebP. I didn't have to do anything. I was like Cloudinary make it better and it just made it better.

COLBY: What browser are you in?

JASON: This is Edge. I don't think I have the flag turned on.

COLBY: Another interesting caveat to that. So it usually will serve ava5th but it also tries to determine the most efficient so some use-cases WebP beats out in the efficiency factor. If that's the case, it will still serve the webP.

JASON: Next I want this to be way smaller. Like 500 pixel square. W underscore for width and height underscore and it will do the processing and crap it squished my head but because Cloudinary is smart I can do a crop of thumb and now it does the magic again and because I said thumbnail it is cropping the image now but I want it to be my face so I can do gravity of faces and that will then say Cloudinary find my face. That's a little too close. I don't want it to be that close. I am going to adjust the zoom. I can do Z_0.75.

COLBY: I didn't know you could do that.

JASON: I have built out, without changing the source image, I have been able to change from a 5 megabyte image would have need today pull into Photoshop and edit down and turn into whatever format they need and crop appropriately. I have now delivered a 500 by 500 image with the right aspect ratio and the right crop for them to use and it is also now 25.7 kilobytes and again served as a webP. This is why I feel like this tool is such a game changer. If I want any image of mine to do this, I can like just copy this section out, right? Let me just copy this and let's go back here and find another image and now I have got the same image. This is another giant image. This one is 5.2 megabytes. Now I am going to go in right here and just paste in the same thing. What did I do? Oh, I put it in the wrong spot that's why. I am now only able to do the exact same thing and I don't have to go and manually do these crops. This is why this so freaking cool sky I lean on it so heavily. Once I solve the problem, it is solved forever. I noticed when I uploaded mine, if I go -- where do you keep these? These are in my head shots. If I go under press, and I find one of these photos, I have all my old photos here, I find one of these, and I am like this is great. This is what I want. But it is not finding my face then you can go in under here where you choose the faces.

COLBY: I didn't know you could do this. You are teaching me stuff.

JASON: There is a bunch of stuff I do on these that is really, really useful. I want to edit contextual metadata. No, that's not it. Did it move? Dang. Move to folder, add to collection. It is in here somewhere. I want to analysis. If I want to like add an area of interest, you can add one of those. I think it has this already. It is area of interest. I want it to show. It has the face and let's me put that in there. If it didn't find my face I could go in and draw a square and mark it as an area of interest and it will then find that face. Just little stuff like this that is so convenient and all buried in context menus and stuff because powerful tools end up being that way. What a game changer that I don't have to open up Photoshop to fix a photo. I can upload here at photo res because if somebody says we should write an article about you in a magazine I have magazine resolution. Seeing that hasn't happened I crop it down for everybody else. [Laughter]

COLBY: Ecommerce is my favorite context. It is the biggest use-cases and one of my favorite. Imaging in an online store with the photographer uploading the images and products but you have no idea what the size is and it can change all of the time. You don't want to constantly have people cut up different sizes so being able to have this ability to do it programmatically and going to the subject. You can do G auto and it will detect the subject automatically. There is different options you can pass in for the gravity value which is the anchor point to do that automatically.

JASON: I don't remember how I did it exactly but this is a cropped and resized version of the full size photo and this is also with a different I think thumbnail gravity here and this one is a regular square crop. That way these photos when you are looking at them small, like this would be kind of hard to tell what's going on if you saw this at this size. By being able to do the crop, I can show the area of interest in the photo and then there is more to it when you actually click through. I feel like that just little stuff like that that I can do programmatically instead of having to manage different size thumbnail assets has made a difference in the ability to make the interfaces of things I am building feel good. That's kind of the -- that's why I reach for Cloudinary when I need to put assets on to a website is because of what it allows me to do here. Then like we talked about, it has historically been more difficult to do that with Next.js because they are trying to push you toward their image processing service and component. So if I want to set one of these up, should I start a new Next project?

COLBY: Sure. You have a ton of Cloudinary assets so let's do a create Next app. We will go Cloudinary/Next.js.

COLBY: I don't know if you know you can do named transformations. If you find yourself doing the same transformations all of the time you can predefine those.

JASON: That would save me a ton of time. We have our node module and pages public. It will open up so we have ourselves a site. I am going to hop in here and probably just delete everything. We don't really need any of that stuff. We now have our very basic site. If I were to -- I am going to do this the way that I would kind of start by doing this. Let's say I am going to make a website for myself. I am going to start with this image. My first instinct would be go with an image. Then add alt and I am done. That does work. We have the image-only on the page but Next is pissed at me. It will let me build this but if I try to deploy it it will fail the deploy which is the most irritating thing about Next.js.

COLBY: So irritating. I don't know why they don't automate it in the build. I am sure there is a technical reason.

JASON: Print warnings and don't fail the build. What an odd hill to die on.

COLBY: I remember like Gatsby and this gets in the difference of frameworks but I remember Gatsby in dev mode gave you the lint warnings. I never understood why Next.js didn't do that same thing.

JASON: They are linting but this is a warning but then instead of marking it as an error that will fail your build it is a warning. ESLint is a rabbit hole that is deep and probably not what we want to talk about today. According to ESLint I need to go use next image but if I try to use next image it will fight me on using my Cloudinary stuff. I instead want to use your library which I would get from where?

COLBY: So the library is next-Cloudinary. We can pull it up. Next-Cloudinary.spacejelly.dev. This is the doc site. Here is the doc site.

COLBY: This is an example of shows the flexibility of it. Just a couple different interesting things going on in this image. We are doing that cropping like you were talking about where we automatically crop to the person in there. We are doing background removal and then we are putting an image underneath and mostly changing the color to make it look more part of the background and adding text on top. There is a ton of things we are doing with within the scope of that component.

JASON: This is, again, this is one of the things that I love. This was all done with code. You just kind of tell Cloudinary to do the thing. This would have taken me forever in Photoshop. I want to use this so I will pop over here. This is what I want. I am going to NPM install Cloudinary Next.js.

COLBY: Before you do that you want to add an environment variable. We need to know where to access your cloud name. So the only thing you need to do is add a next public Cloudinary cloud name environment variable.

JASON: I just want to be able to deploy this without having to setup the environment variables so I am going to deploy first and then we will keep it going. I am going to get commit. We are going to say work in progress. Then I need to GitHub and create. If you add the org name it will create it in your org. You can cut and paste this. I want remote and push everything here up to that remote. Because I am in terminal, iterm, I can click this and it will take me to this old buddy. Don't need Netlify because it is on the Learn With Jason.

COLBY: I saw the organization GIF. Didn't know you could set GIFs. That was amazing.

JASON: Go to next. There it is. I don't need to configure anything so I will deploy the site. I am going to go into site settings and there is this ID here. I am going to copy that and I am going to Netlify link and enter the site ID because that's nice and fast and now my site is linked.

COLBY: I don't know who added that but that's a game changer.

JASON: Now I can set environment variables using Netlify and set and what is the variable that we need?

COLBY: Next_public_Cloudinary or you can copy and paste it from the documentation.

JASON: Do this and my cloud link name is here. I am set that. When I run Netlify dev it will grab this environment variable but importantly this is now available to deploys. So that is a big deal. The way this works if you are in the new specious is it chose what we created. -- experiences. If I needed to and since this is the cloud name I will show it. You can see the values here. If I want to to work differently on local dev and have a production cloud I would also edit these values so you can keep them like separate for local staging production Etc.

COLBY: That's super handy.

JASON: There is a lot there. It is worth checking out. It is very cool. It is new. We haven't talked about it a bunch but I am really excited about it. It has solved some big problems for me.

COLBY: That's awesome.

JASON: Environment variable set. We are back up and running. I have it installed.

COLBY: Let's import and destructure ClID image. At this point you should be able to just swap the image tag. The only thing I think you will require a width and a height. I think those are the only two other attributes that are required. I think technically it will take in the Cloudinary URL. It tries to parse it. It is not always able to. We can see if it works first. What we will want to do is just take the URL and just only apply the public ID. Cut off everything until the upload parameter. I had to get rid of the first slash as well.

JASON: We eliminated all my optimization so these are big images.

COLBY: You set it as a square but the image isn't a square, right? That's why we are seeing a little warped. We can fix that super easily. Since we have the props based API, we can add a prop of crop and we can set that to fill or thumb if you prefer. And that should be able to reload. If you wait a second, I think it will reload in the background after the image is actually downloaded but it won't do it until then. It was already updated. It uses G auto or a gravity of auto so it will automatically set that crop to the subject. You don't use usually need to do all those things but you could set a space and might get a different result since you want it to specifically look for a face.

JASON: Got it. Nice. Why is this yelling at me? Couldn't find a declaration file.

COLBY: I haven't gone into TypeScript yet. I know I need to do. I haven't learned it yet.

JASON: Do I have a zoom probability -- property or a way to add arbitrary transformations?

COLBY: I set it back to fall transformations. I have been adding the qualifiers because I didn't want to plaster every single one of them in there. It will be an array. An array of strings that should work like that. The only thing with the Zoom is I think it might have to be coupled to the primary transformation. When you are doing the different transformations, you have the different blocks. I guess my hands should be angled the other way. You have the different blocks of the transformations ask when you have the chain the way you have it in the original URL the zoom was applying to the transformation. That zoom is happening after the transformation. I need add the zoom prop so it will attribute it to the actual thing.

JASON: In the meantime I would need to do one of these?

COLBY: It should be one full string but yeah.

JASON: I got it.

COLBY: Making a node I need to add that.

COLBY: Let's look at the source URL. What you need to do is add the width and height to the raw transformation string. This is why I was excited to come on because you will help me find the holes in this.

JASON: Here we go. This is getting us where we want to go. Yeah, we are getting all these details. It is pulling everything together for us. I can kind of start to figure out where we want this to go. It actually looks like because we have added other things we might not need this piece.

COLBY: You updated to faces, right?

JASON: I did update to faces. That's going to be fine for now. This is kind of doing the thing. This is great. Let's do it with one where we can like drop the background out and do some different stuff. Let's go grab, where is one that is easy to crop? Here is this one. It looks like it should be.

COLBY: That should be good. You can probably just copy the ID at the top.

JASON: Let's go in here. I am going to drop this piece in and what's the 6400 by 4267?

COLBY: One interesting thing. If you are not doing the -- what I usually setup the images I add the responsive sizing and when you use that you don't need to worry about the sizing and making sure it has the right ratio because at that point the responsive sizing controls what the width and hide are going to be.

JASON: How does one turn on the responsive sizing?

COLBY: You can use the sizing attribute and you can set it lazily to 100 view port width right now. I think you need your width and height in there also. You don't need to have the specific width and height of the image. It can be something that's going to express the ratio of that image.

JASON: Oh, I gotcha. We can set the -- what is it? 6200 by -- 6400 by 4267. Back to here. Now if we inspect the image, the image is blowing up out of the container. If we look at that, we see the responsive sizes now and those are all being added by Cloudinary. The Next.js is doing that logic to generate all those sizes but then plugs it into the Cloudinary URL. It works really well.

JASON: I would need to add styling.

COLBY: If you go to the global file, I add a max of 100% and set the height auto. That usually serves me pretty well. Yeah. I usually do max width 100% so it is not the container. Yeah.

JASON: We have overridden the thing and it is now showing us a max width of a 100% so it is the container and not the view port width and the height auto over rides so the aspect ratio is defaulted. Cool.

COLBY: Did you want to crop that or remove the background right away?

JASON: You tell me.

COLBY: Let's add prop is remove background camel case. You don't need to add a value. You can add true but just the prop itself. What is going to happen in the background is if you go back to your console if you have that open, you can probably refresh and see this as well but we see we are getting -- why a 420? Can you open that up and we can see? Here is a trick if you haven't heard of it before. If you look in your request headers, or response headers rather, CLD returns a header that gives you the error. You don't have an active subscription. It requires the Cloudinary AI background removal. Let's add the add-on. The add-ons are that puzzle piece up there. Then it is going to be that top-left one. There is a nice free tier for us to play around with. You can click that.

JASON: I have successfully subscribed.

COLBY: We can probably add a version to avoid that cache or switch to a different image. I haven't tried adding the version that way. Let's see if that works.

JASON: I think you have to do it with these. You have to use an actual version or it gets grumpy.

COLBY: It usually does a pretty good job with the background removal. I built a photo booth app I have been taking to events and it does a good job removing the background. What's happening now is the processing for the background removal is asynchronous. It can take a really long time or a really short time but it doesn't know that right away so rather than just having that image hang and hang in the background it is going to return that 423 meaning it is processing. After it processes, it is going to cache that and serve it as-is from there on out. It won't happen every time but you have to get the first load to happen first before it can remove the background. I think it was a decentally big image so it might take a few seconds.

JASON: Is it going auto reload once it is done?

COLBY: Somebody is working on a pull request for that or I will have to do myself because now there is an on error attribute in Next.js so I want to pull for the asset after that error message occurs and once it is loaded just swap that in.

JASON: Nice-nice.

COLBY: In the meantime we can remove that. Since we know it is getting removed in the background we can do something else or we can -- yeah.

JASON: Let's leave it off for now. We will add it back.

COLBY: Let's go to the documentation and we can look at the different examples of the props we can work with. Here.

JASON: If we go under the left sidebar under examples, there is a lot of different things we can do. The zoom and pan one is fun. You know the Ken Burns effect where it takes a still image and it can kind of move around. This is that. So by default it is just going to use gravity Avado again and zoom into the subject. But you can set all your coordinates and whether you want to zoom to or from and a lot of different things. I think you probably want loop, yeah. This will take a second to load the first time as well since it is processing that in the background.

JASON: We have the zoom pan. Pixelate? That's fun. Let's go get a smaller image. This is going to kill us. I have some stuff that is not so absurdly large. Let's go with this. This is a small image. 60 kilobytes. That should be fine. Now

COLBY: If you reload the page it will be cached and reload right away. For F auto you can have it do F auto for everything but I think it is call and animate and you can set it so it will automatically determine the best animated format to serve which is interesting.

JASON: Oh, that's nice. Gray scale. You can do tints. Cropping. It has the auto gravity.

COLBY: I need to figure out how to better show the place limits. Those are the blurred placeholders like the tiny ones.

JASON: These are cool, though. Placeholder blur and then I am going to switch this out. Let's save it. Let's maybe turn on the throttling. We go go with the slow here and make this taller so we can see what is going on. This is 3G performance. We have to download the markup and the JSON and Bootstrap that JavaScript and rehydrate the page and get stuff. Why is this so big? What on earth is causing this? Maybe we try this again. Whoa. That is a decent amount. Next maybe you need fast 3G.

COLBY: Do you have to refresh? Or will it automatically update? That's cool. I didn't know that.

JASON: Geez. That is brutal. Let's try that one more time. Is is still too fast.

COLBY: Back to the big image. No.

JASON: This is great. I wonder if that preloaded in the background because the next step was taking so long. Anyways, placeholders are cool. You can see the flicker of it. It is just -- by default, Next.js has its own by default. What I wanted to do was try to provide some kind of variation on top of it. I don't know. There is only so much you are able to do because it actually, Next.js, is blurring it in the dom, or they were in next 12. I want to create the SVG placeholders. I wanted to provide that option and couldn't do that because of the blurring that was happening.

JASON: Got it. Still very cool. Lots you can get away with here. Let's do this. I want to kind of -- you did this cool thing where we replaced the background on this. Let's remove the background here. Remove background. It isn't going to work because it is super weird.

COLBY: I am curious to see what it looks like. It does work with text.

JASON: I have my suspicions this is going to go strangely.

COLBY: Or the best way.

JASON: I don't know how long to expect this to take.

COLBY: I would say 10-20 seconds for smaller images.

JASON: Do we have anything in here --

COLBY: I think by the time you find it it will probably be done.

JASON: I think you probably right. Those are all videos.

COLBY: You can also do background removal with videos. Fun fact. I took the shilaw lubuff video, green screen one, and it was a lot of fun.

JASON: Amazing. These are guests. I am not going to mess with guests.

COLBY: You can mess with me.

JASON: OK. Let's find you. Crap. They all have custom names. Upload asset names.

COLBY: Yeah.

JASON: Crap.

COLBY: Let's see if it is done. Maybe it is. Yeah. There we go. It is not perfect.

JASON: Chaotic results. If we move this around, you can see where the background is on it. If I change this to let's replace this background, is it here, background and we will make it red.

COLBY: Just to clarify for the audience, this isn't the intent. This is a tricky one. It is helpful for our example.

JASON: Yeah. So we've got that. We have somewhere in here, I don't know what we want. I have all these images I have done at different points. Is this one smaller? Here is a much smaller version that we can mess with. This one is just in -- we have a lot of -- OK. This is a smaller image that should theoretically 20 seconds or so be usable with the background knocked out. We will see how -- it can scout a lot of different things going here so we will see.

COLBY: I am confident in it.

JASON: Then we can try to put something else in the background. I want to be hanging out -- that's an animated GIF. Never mind.

COLBY: I wonder if that would work. Try putting a GIF as a background. I have got another image here that we can use. And that's going to be here. I have got my cloud name ready. If I want to put a new background in after I remove the background, what do I do?

COLBY: We will use something called underlays. Typically you can create an underlays property and do an array but I created a helper way to do it quickly so you can use the under lay like you have and we can string and pass in the public ID and that should be it.

JASON: Oh really? That's easier than I expected. We will drop it in and see if it is done. It is.

COLBY: Look how cool that is. You covered up Marissa. This is great and one image. If we open in a few tab this isn't multiple images. This is very much one specific image. I think

COLBY: I think it is interesting because with Photoshop you have layers and what we are doing is taking the base image of you, that's the base layer, and we have the underlay which is shoving something underneath and that's the backgrounds image. The overlay is there text and things on top.

JASON: Let's do one of those. That sounds fun. Is it the same thing?

COLBY: I don't think I have a helper method with that one. I think you need to define. We have two different things. You can do text which is the text prop and you can add a string. So let's try that and we can play around with that. Then you can add something. Yeah. By default it is going to be just like black text, very simple, just shoved on there. As an easy way if you want to add text. Not everybody wants to do it that way. For this, I am going to have you copy and paste the documentation because I don't know the exact things but if you go go all of the way down on the left, I am sorry on the sidebar, and then do text overlays you should be able to copy one of the text objects. You can just -- so I have that in the overlays format. I didn't update that. You can copy all the information inside that text object.

JASON: Like this?

COLBY: Yup.

JASON: Instead of this then I would do --

COLBY: Exactly. Perfect.

JASON: Good. Good. Then we can just start -- and letter spacing.

COLBY: Some of the stuff we were doing before isn't as visually exciting but practical. This is more fun stuff like seeing the visual impact of the text and different images and playing with those different layers.

JASON: Right. Yeah. What if we just want to go full meme format? I want to position this toward the bottom with a black border. How would one do such a thing?

COLBY: Let's break into the overlays format. You can copy that same object from inside of the text prop but now let's add an overlay. We are going to create -- so create an object first and then text is going to be the first property of that object. There you go. Yeah. Now in addition to that, we want to add a property of position and that's where we are going to do all of our different coordinates. You can set the gravity which if you want that to be on the bottom you can actually set the gravity -- gravity. I don't have to do the thing. And south. If you wanted to add a Y value you can certainly do that as well.

JASON: OK. And so Y would be like the number of pixels I wanted off the bottom?

COLBY: Yeah, and that's going to be relative to I think the original size depending how much you want to space that out. Yeah. Cool.

JASON: Maybe a little bit more. Let's go like 80. OK. Happy.

COLBY: We are going to do one at the top?

JASON: Sure. Same deal here?

COLBY: Yeah, you will just add another object to that array. Duplicate it. Just a quick note for people watching about gravity. Gravity is going to be that anchor point. A lot of the basic examples of gravity are compass direction but then we have the AI-based one with auto and faces and that's what you are seeing for those different values.

JASON: Got it.

COLBY: We have the meme. It is beautiful.

JASON: I am missing the key point where we need to outline the text or you can't read it.

COLBY: Let me check for that property. That one is in there. It is outline. You should be able to -- there is a default option. If you pass in outline. No, sorry. That's the proper on the actual image itself. Let me find the overlay. Don't tell me I don't have that. It is border. Border. Border and then you also need to do stroke of true. It is the difference in what it is trying to do. It is telling it apply the border. For the value of border, try something like CSS 20 pix solid_black maybe? I am kind of simplifying the property names but haven't abstracted the values. I want to think through that more before I do anything more comply -- comp calculated with that.

JASON: I think that's the right call. If you pre-abstract some of this stuff it is hard to do. I see something getting clipped but it is close enough. If I was going to do it for real I would find another way to solve that problem. This is fun. I think I have dealt with this. There is a bounding box that has to be set to be a 100% and then make the text centered. But yeah. This is fun. So now you've got the ability to make a meme thing. You can go in and set --

COLBY: Just with that one component.

JASON: What's really fun is if you can imagine you could make this dynamic. You could create a meme builder on your site using this component and take input from the forms and then drop them in here and you would be able to generate memes on the fly. If you wanted to make a meme builder which we don't have to do today unfortunately if is not that wild to imagine you can go in and create this. That's the part I find so exciting. I don't want or need to be how to open a canvas element and build out images and then kind of export those as JPEG. If I am doing it as canvas it isn't optimized. I could generate memes on the fly, let them upload and copy and paste it, but I can generate an image with a source sed so they had all of the right versions. -- set. Copy and paste this on your website and it will be performant. How much time do we have left?

COLBY: Let's do one more thing. If you scroll up to imports inside the code. Let's do CLD add an additional CLD OG image. Copy and paste that image that you have, the same image that you have, like just copy and paste that. Like the entire thing.

JASON: Got it.

COLBY: You can paste it under the head. It can't be in the head but under the head. The only thing you need to do is remove the width, height and sizes and of course update the tag which you did. Now let's save that. And now you should be able to inspect your head and let's see what that does. We get a perfect open graph image. It uses the same API has the CLD image but handles all the work of generating meta tags so you can just as easily create our open graph images like you were doing for your site, right?

JASON: Yeah, this is awesome. I think the thing that I always find with these is that it makes me willing to do some of the work that is important for making websites, like, first of all, performant. Like all the different open graph image and sizes and things like that. If we look at this, we are not just generating an image. We are generating a full stop helping. Get out of the way. We have a full source set here. If you look, it is the same image many times over but it has got different settings for the width and stuff like that. It is showing us the rendered and intrinic size and which current course we are using. I find these cool. We are looking at the full-full size and smaller and smaller. If I open this on a phone it will probably open the 750 or something which is a much smaller imagine than the full size one. That happened. I didn't have to do it. It just did it for me. Because it is API driven, it all just kinds of works on every image and you know, I set the sizes up once and it happens. Or I didn't set-up anything. I trust the framework and your tool to do that performance optimization for me. But the other piece of this that I really like is when you start looking at these things like we just kind of emerged by playing with this tool we could make a meme generator. I would not have thought to tackle that if the tool didn't make it easy. I would have been like that's a lot of work for something that already exists. There is image flip and meme generator and stuff like that but it would be funny to put one of these on my website. I just wouldn't have done it if it wasn't like Cloudinary let's me put in an element and I have to put in a couple and I am off to the races.

COLBY: I am glad it is proving to be value. I am excited to hear thoughts. Still telling people it exists but if anyone plays with it I would love to hear suggestions or feature ideas you find missing from Cloudinary.

JASON: Chat, go forth and make butt memes. Colby, this has been great. Where should people go outside of this page here if they want to learn more?

COLBY: Outside of that page?

JASON: I am going to tell them to follow you on Twitter.

COLBY: Every @Colbyfayock. More basic stuff we went through. Which discord?

COLBY: I have spacejelly.dev/discord. It isn't super active but would love for anybody to stop by and say hi.

JASON: That's going to auto correct, I assume? Yes. With that, I think we are going to call this one a massive success. You could say it was a butt load of success. [Laughter] thanks, again, as always to Maggie who I... I am so sorry, Maggie, for making you write this nonsense down. Maggie is here from White Coat Captioning and that is maze possible through the support of our sponsors, Netlify, New Relic, NX. While you are checking out things on the site, make sure you go and check out the schedule. We have all sorts of fun things. We are going to do fido 2 fingerprint login through your device into aps. We are going to talk about optimizing React performance. We are going to learn about docusource 2.0. And I have a few in the hopper not up on the site yet so stay tuned. Colby, any parting words?

COLBY: I was waiting to see in the captioning a line from Maggie that says not amused --

Maggie: Ha!

JASON: Constant professionals. Maggie would never.

Maggie: Never!

JASON: She is going to pull a muscle from rolling her eyes so hard. All right. With that, we are going to call this one a success and find somebody to raid. I don't know who is live right now. I am just going to start digging and see what we can find. Let's look at who is doing JavaScript right now. We got a few folks doing JavaScript. It looks like coding garden is doing dino and fresh. That's kinds of fun. Let's go raid coding garden. Colby, thank you so much for spending time today. This was an absolute blast. Chat, as always, thanks for spending time with us. We will see you all next time. See

Learn With Jason is made possible by our sponsors: