Javascript Fun: Build a Photo Effects App! | Chris Dixon | Skillshare

Javascript Fun: Build a Photo Effects App!

Chris Dixon, Web Developer & Online Teacher

Javascript Fun: Build a Photo Effects App!

Chris Dixon, Web Developer & Online Teacher

Play Speed
  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x
11 Lessons (1h 5m)
    • 1. Welcome To The Class!

      2:34
    • 2. Creating The User Interface

      7:23
    • 3. Styling With CSS

      8:25
    • 4. Drawing To The Canvas

      10:46
    • 5. Uploading Images

      6:56
    • 6. Understanding Pixel Data

      5:56
    • 7. Looping Through Image Data

      6:22
    • 8. Greyscale, Sepia & Invert Functions

      4:51
    • 9. Adding Additional Effects

      5:53
    • 10. Clear & Download Image

      5:26
    • 11. Follow Me On Skillshare!

      0:23
  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels
  • Beg/Int level
  • Int/Adv level

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

708

Students

3

Projects

About This Class

Welcome to the Javascript fun series!

You can find all of the code, resources, and project stages here:

https://github.com/chrisdixon161/fun-javascript-projects.com

For web design or development, there are 3 must-know technologies, HTML, CSS, and Javascript.

The main aim of the Javascript fun series is to take your knowledge of these 3 (only a little is required!), and put them into practice by building a series of educational, yet fun projects that show you exactly how they work perfectly together. Working on projects and solving problems is a great way to learn.

The project we will build in this course will be a Javascript Photo Editing App.

All the required tools are free to download, I will be using the following:

Visual Studio Code Text Editor: https://code.visualstudio.com

Chrome Web Browser: https://www.google.co.uk/chrome/browser

We begin by creating the user interface with HTML. Then we apply styling using CSS.

Then we add Javascript, this is where the real magic happens!

You will learn things such as:

  • Creating HTML interfaces
  • Styling with CSS
  • Incorporating Javascript and linking external files
  • Const and let
  • ES6 Arrow Functions
  • Event handlers
  • Manipulating the DOM
  • Drawing to the canvas
  • Loops
  • Using the canvas 2d context
  • Working with file readers
  • Uploading images
  • How pixels are structured
  • Looping through pixel data
  • Manipulating and replacing pixels on the canvas
  • Downloading Images
  • And much more!

So if you are looking to move on and put your skills into practice using real projects, I look forward to seeing you in class!

Meet Your Teacher

Teacher Profile Image

Chris Dixon

Web Developer & Online Teacher

Top Teacher

Hello, My name is Chris and I am a web developer and online teacher. I am passionate about what I do and about teaching others. I have started various online and offline businesses.

Whatever your reason for learning to build websites you have made an excellent career choice.

My personal motivation was to become my own boss and have more freedom and flexibility in my life. I also enjoy the technical challenge it provides and the way it constantly evolves. I built my first website back in 1999 and i have watched the web evolve into what it is today.

I try to make my courses enjoyable and try to remember what it was like when I was learning. I also believe the best way to learn is by doing and try to include as many practical examples as possible in my courses.

... See full profile

Class Ratings

Expectations Met?
  • Exceeded!
    0%
  • Yes
    0%
  • Somewhat
    0%
  • Not really
    0%
Reviews Archive

In October 2018, we updated our review system to improve the way we collect feedback. Below are the reviews written before that update.

Your creative journey starts here.

  • Unlimited access to every class
  • Supportive online creative community
  • Learn offline with Skillshare’s app

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

phone

Transcripts

1. Welcome To The Class!: Hey, welcome to this class. If you are a web development beginner and want to just jump in and build some fun projects, you've came to the right place. The idea behind this series is to show you what you can do with regular HTML, CSS, and JavaScript. I'm not confusing any frameworks, any boilerplate, any libraries or any templates. Instead, we're going to be building everything completely from scratch, step-by-step to show you how these free technologies all work together. With this project we're going to create a photo effects application. It's going to involve creating a photo uploader where we can select the image from our computer. I select one just here, and once we open this up, this file will then be displayed inside the browser. This is the original image and then over on the right we have some options to change the effect. We can change this to be grayscale. We can add things such as a Sepia effect. We can invert the colors. Images are made up of pixels which are red, green, and blue values. We also have some options to switch around the order of these colors too. This gives us some nice looking effect, which can really change the look and feel of our images. Once we are done and we have a nice looking image which you want to use, we can also download this image too. This project will give you a chance to learn lots of new things. We'll create a user interface with HTML. We will then add styling with CSS. But the main focus in this video is going to be the JavaScript, and also working with pixels. You will learn how to upload images, create file reader objects, how to draw to the HTML canvas. Then once we have that image in the canvas, you will learn how to read all of the pixels from this image. We'll then loop through all of these pixels and apply various effects. We'll also learn how to reinstate the original image and also download the modified version too. If this sounds really complex, don't worry. This course is designed for beginners. However, little JavaScript knowledge would be a real advantage, and ideally this should be the fifth project which you take from this JavaScript from series. All of the other projects are also available here on Skillshare. It would really benefit to take these classes in order. Hope you're now excited to build this photo effects up and I'll see you inside the class. 2. Creating The User Interface: Welcome to our next project, which is the photo effects application. The user interface is going to be relatively straightforward, especially in comparison to some of the other projects. All we're going to do is to create a sidebar over on the right-hand side. This is going to have a series of buttons which are going to create an effect on a photo which is being uploaded. We can go ahead and select the file, choose an image, and then this will display this inside the browser. Then have a series of effects. We can make this a grayscale effect. We can clear these effects. We have invert, we have the sepia effect, and then we have a series of buttons, which is going to switch around our red, green, and blue values. This is going to give us some different effects such as this. This is going to give us a more red shade. An effect that this has is going to be pretty different on each image. To do this, we're going to swap around all the pixels on the image to give us these nice looking effects. We also have the facility to download this image. We can click on this button. This will then download the image for us to use. As with any of the projects on this course, you can use an image of your choice. Or if you want to use the same image that I've used for this project, head over to the GitHub repository, and then you can go into the Photo Effects application, where you will see not only the sample code once this is uploaded but also the image which I'm using during this course. To get started, I'm going to download this. Click on the image name, click on "Download". We can then right-click, "Save" our image. I'm going to save this on the desktop. We also need a project folder. Let's head back to our desktop, New Folder, which is going to be the photo effects. Drag this over into our Visual Studio Code and then let's make sure our image is available inside of our project folder. Let's drag this over and drop this into our project folder. Step one is going to be to create a new file, which is for our index page. This is going to be the index.html. We can then open this up in the browser, copy the path to this, paste this in, and we are good to go. Let's begin with our HTML structure. As ever, I'm going to use the html:5 command, which is built into Visual Studio Code. The document title is the Photo Effects App. Then inside the body, we are going to surround all of the photo area inside of the main element. We'll then have the aside section, which is going to be our sidebar. This is for all of our buttons and the image upload. The main section is going to be pretty straightforward. This is simply the area which is going to display our image inside the browser. The way we're going to do this is by creating a canvas element. A canvas is a HTML element which we'll be using to draw our images to. It can be used to draw almost any type of graphics from lines and shapes, photos, ripe fruits, complex, 3D objects, although in this course we will only access the 2D features, more specifically the 2D context and we'll take a look at this in more detail in the JavaScript. We need to create a canvas element and then an ID which is going to be canvas too. This is just so we can select this element in our JavaScript, and then we can draw our images. Next up the aside section, which is going to contain our uploader and our buttons. The first section is going to be a div with the class of input-wrapper. This is going to be the section which is going to have our label and also the file uploader. The label for this input will have an ID of uploader and then the text of select file. After this, a input, and the input type for this is going to be file with the ID of uploader. We can then use this inside of our JavaScript and this also matches our label just above. Next, after our input wrapper, we can create a second div. This div is going to have the class of effects. This is going to be the area where we select all of the effects using these buttons. The first button, this is going to trigger the grayscale effect. The second button, this is for the sepia effect. The third one is going to be for invert. The fourth one, this is going to be the start of the four buttons, which we are going to switch around our red, green, and blue values. The first one is going to convert the red, green, and blue to be red, blue, and green. Let's duplicate this to create four buttons. We're always going to start with the RGB color. The left-hand side will always be the same. However, for the second button, this is going to be switched to be blue, green, and red. The next one is going to be green, blue then red. The fourth combination we're going to use is green, red, and then blue. If this color combination I'm switching around doesn't make sense at the moment, that's fine. This will all become more clear when we take a look at pixels in the JavaScript section. After our effects section, we're going to create a new div. This div is going to have the class of controls and this is going to have our clear and also our download buttons. The first one of clear and the second one is so our user can download this image. Give this a save or we could even open this up with our live server if you've chose to use this during this project. Let's open this up. Go to View and the Command Palette, where we can take a look for our live server and we can open this up with our live server extension. Now inside the browser, we have a pretty terrible looking application, but all of the content is in place. Let's style it in the next video. 3. Styling With CSS: It's fine for this project is going to be pretty straightforward. We're just going to create a background color and then add some colors to our buttons along with some responsive layout. Since the styling is pretty straightforward, I'm going to just start this over the top of our index page. Just inside of the head section, we can create the style section, and if you want to keep this separate and places into a separate style sheet. The html is going to be used to set the base font size of 10 pixels. The body section, all we're going to do here is to set a background color, and then we're going to create our responsive layout. We're going to use the flexbox. Then on the smaller screens, we'll set our sidebar and our main section to be the display type of column. Then we'll change this on the larger screens to be the type of row. First of all, the background-color, which I'm going to be using as a rgb value. The red color is going to be 48 and 47 for the green value, and the same for the blue. The display type is going to be the flexbox and we can change the flex direction to be column. We don't see much of a difference at the minute bulb. We're go to separate these two sections by making the main section three times as wide as the sidebar. Let's make this a little wider. Can again take advantage of the flexbox and set the main section to have a flex value of three. To make this work, we also need to set the side section. This is going to have a flex value of one. For reload, we don't see any effect on the page. This is occurring because we have the flex direction set to column. To make this work more on the larger screens, we need to add a media query to change the flex direction to be back to row. Let's add @media. Where we can set our minimum width to be a value of our choice. I'm going to go for a value which is going to be 1,000 pixels. The only thing we need to do inside here is to target our body section, and then change the flex direction to be row or to the browser. Now if make this a little larger, we see the flex value of three. For our main section, only sidebar has a flex value of one, meaning it's one-third of the size. Reducing this down to 1,000 pixels or below will return our flex directions to be back to column for our smaller screen. For the sidebar on the larger view, we're also going to add just a little margin on the left-hand side to give us some space from our image. The sides section, we can set the margin on the left of 0.5rems. Then we're going to get to work with these buttons. The buttons are for all of our effects and also the clear and the download buttons. The background is going to be an rgb value of 21, 20 and 20. Let's make these a little larger with some Padding. So 1.6rems on the top, zero on the right will keep this consistent with the top and at 1.6rems on the bottom and then add 2rems on the left-hand side, which is going to give us some spacing from the left of bottom. The font size of 1.6rems, which is 16 pixels. The cursor is going to be set to be a pointer, when the user hovers over any of these buttons. The color so we can see the text. This is going to be an rgb value. The red is 212, 210 for the green, and the blue value of 210. Given our text a lighter colors, so it stands out more. We can also remove this default border by setting this to a value of none. Then we can use our own border on the very bottom to give us a white line between each one of these buttons. This white line is going to be one pixel wide and a solid color. Next we're going to add a hover effect to our buttons. We do this with the hover state. All we need to do here is to give his background color a slight change. The value I'm going to go for is a rgb value of 50, 47 and 47. Let's give this a try. That's all good. Now we're going to put all these buttons onto their own lines. This is relatively straightforward all we need to do is to target our effects class, which is the div wrapper for all of these buttons down in our HTML. Let's target our effects. We need to set the display type to be flex. Then to make these vertical, we can set the flex direction to be column. Down to our controls, which is the Clear and the Download button. We are going to make sure each one of these buttons takes up half the width of the available space. Again, we're going to make use of the display type of flex, and then we can target each one of our buttons, which are nested inside of this control section. If we set the flex to be a value of one, this is going to make sure that each one of our buttons inside of the section is going to take open equal amounts of space. We still have a board on the very bottom so we can remove this with border-bottom none. If we scroll up, the next thing we're going to do is to move all of the texts, these buttons to be over on the left. We can do this by setting the text align to be left. Then for our two buttons on the bottom, we can reinstate this by setting this to be a text-align and to be center. We can also remove the padding values for this Clear and Download button. The padding. Let's go for 1.6rems on the top and bottom and zero on the left and right, which will then pull our text into the center of our buttons. Back up to the top we have this section which has a label and also a input. Let's begin with our label. Set the font size to be a little larger. So 1.8rems. If we also stretch the browser to be a wider size. When these two elements are alongside each other. We also need some padding on the right of this label. I want to add 1.6rems. Both this label and also the input was surrounded in a div called input wrapper. Now we're going to use this and add some padding and also a background color. This was the class, so we use the dot. The background wants to give this a simple color of gray and also a padding value of 1.6rems. Then to finish this CSS section off, we're going to select our canvas section, which is over on the left-hand side in the main section, and then set this to be 100 percent of the available space. That's all we're going to do. We can go ahead and make some more changes. What someone's keep the style of this project reasonably simple, and then in the next video, I'll move on to drawing to the Canvas. 4. Drawing To The Canvas: To make this project now come to life, we need to add a script and also discover how we can draw to the canvas. At the bottom of our index or html, just above the clause and body, let's add our script with the source of script.js. Over to the sidebar, we can now create this script.js. Now we've got a canvas elements inside of our html, and this also has the ID of canvas. But how do we actually go about drawing to this canvas? Well, the first thing we want to do is to create a constant called canvas. Inside here, we're going to select this canvas by the ID, so getElementByID and the ID was canvas. This is now giving us our reference to our html element. We then need to access what is called the rendering context. This will allow us to access a range of drawing functions, so we can manipulate what is on the canvas. The way we can do this is by accessing our canvas elements, which we restored above. We can access the context by using a method called getContext. We're only going to be accessing the 2D features, so we pass in 2D. Then we're going to store this in a constant called ctx. The ctx references is used each time we want to draw to the canvas. For example, this context has a fillText method to draw a text onto our canvas. Let's access our context, and then we can make use of one of these drawing functions which we mentioned, which is going to be called fillText. Inside here as a string, we're going to pass in some text which we want to display onto the canvas. Add anything inside here. We can then add two more values, which is the width and also the height. Let's go for 100 pixels and 50 pixels. Then let's see this over in the browser. Take this down. The darker text color doesn't stand out too much, but this is now our text on the canvas. We can also create shapes such as a rectangle, and we can also either use the stroke, which is the outline of the rectangle or the shape, or we can use a fill which is going to create a filled shape. Let's take a look at how we can create a rectangle in the canvas. We, again, access the context. We can then fill a rectangle with fillRect. We're then going to pass in all different values. The first two, easy x and y coordinates of the canvas where we would like to start this rectangle. If we entered a x value is zero and the y value is zero, this replace our rectangle on the top left corner of the canvas. A third and fourth values are going to be the size of the rectangle. If want this to be 50 by 100, this is now 50 pixels wide and 100 tall. If we didn't want this solid color and we just wanted an outline, we could change this to the strokeRect. This stroke and this fill can also apply when we create different shapes too. Rather than specifying a fixed size just like this, we can also access our canvas object and pass this in as a variable. We can set the canvas width and also the canvas, the height. This is now going to give us a rectangle which is the height and the width of the canvas. We can also use different colored objects too. The way we can change the color is by accessing the context and then using the fillStyle. I want to set this next rectangles be equal to the x value of 42e9f5. Let's now move this up above our rectangle. We can change this to be a filledRectangle and also make this a little smaller. Let's change this to be 50 by 50 to give us a square. Another example of what we can do with the canvas is to draw some lines to create some more complex shapes. For example, if we wanted to create something like a triangle, we can then create a series of lines to create the shape. We're going to begin our shape with ctx.beginPath. BeginPath will start or reset any existing paths which we created above. After this, we're going to declare exactly whereabout on the canvas, we want to begin our join. For example, if we wanted to start this at the very center of the canvas, we will do ctx.moveTo. MoveTo is going to move our reference points to any place on the canvas without actually drawing any lines. The way we can place this into the center is by setting the canvas.width, and then divide it by 2 to place this into the center. Then we can do the same for the canvas.height by dividing this by 2. Right now, we should be in a position where we're ready to draw some straight lines from the center of our canvas. We access our context and then lineTo. If you wanted to draw a line to the top right-hand corner, the coordinates we need at the moment are 300 and zero. So 300 for the x value and zero for the y value. Why do we need these two exact values? Well, this is because by default, the canvas is 300 pixels wide by 150 pixels tall. If this position in the top-left is zero, zero, the first value of 300, we'll place this right at the very end. We then use the zero value to stay at the very top of the canvas. If we added any other values inside of here, this will then push this further down. We've actually created our first line with the series on the canvas. We also need to use ctx.stroke. Then all we need to do from here is to create a series of lines. The next one, if we want to make this from the top right down to the bottom right, we start by keeping the x value as 300, which is right at the very end. As we described the canvas height by default is going to be 150, but this leaves us a line from the top right to the bottom right. If we wanted to enjoin this back into the center, we then have two options. We could go ahead and create a new line just like we did with these two lines of code, or instead, we can move back to the beginning, which is the center of the canvas by using ctx.closePath. I will now have a triangle. If we wanted to fill this with a solid color, we could replace the stroke with fill. This is now a basic introduction to join on the canvas. This is all great, but we don't need any of this for our project. Instead, we need to draw a image onto this canvas. Instead, we're going to remove this section, and we can create a new image elements. We can create a new image elements with new image. This new image constructor is going to create a new image elements just like we did when we use documents.CreateElements. Throw this in a constant called img. Next, we need to set a image source. We need to grab our image and set the source attribute to be equal to our image, which is bridge.jpg. Remember to change this image source if you have used a different image. We now have a new image elements and we've set the source. Now we need to position this on the canvas. But just before we do this, we need to actually make sure that this image has been created before we tried to draw this on the canvas. The way we can do with this is by using onload, which is going to run a function once our image has been created. Inside this function, we're going to draw our new image to the canvas. As ever, we select our context, and then we have access to drawImage. The first thing we need to add in is the image, which you want to draw, and this is our image variable. Then we set the position on the canvas where we want this image to be displayed. If we set this to be zero and zero, this will be displayed from the top left-hand corner. We now see an image on the screen, but the image is far too big for the canvas. Another thing we can do is to add two more values, and this is to set the image width and height. If we set this to be 300 with the height and at 150 for the width, this will now make sure our image is now the same size as the canvas. Even though we now see this image on the screen, it doesn't look too high-quality. Now, this is because the image has now been stretched to be the same size as a canvas. However, we can switch it around and make sure that the canvas is then expanded to be the same size as the image. Let's do this just above where we draw our image. We can set the width of our canvas with canvas.width to be equal to the width of our image. Just below, exactly the same for our height, we set the canvas height to be equal to our image height. We can move the last two values where we set our image size inside the drawImage. This will now give us a clear image since the canvas is now stretched to be the same size as the image. This is a basic overview of some of the things we can deal with the canvas. But we only going to be using this to add images and manipulate the pixels. Next, we want to make use of our file uploader, which we added at the top of this sidebar. This is going to allow the user to select an image of their computer rather than using this hard-coded value just here. 5. Uploading Images: Displaying an image on the screen or onto the canvas is now a big step towards our application working. But the next thing we want to do is to allow the user to click on the file uploader, select a image of their choice, and then display this to the canvas. At the moment, we're just hard coding an image source with the image which is inside of our project folder. That's what we're going to do now in this video. We're going to begin by creating a new FileReader object, and then we can store this inside of a constant called reader. This FileReader is going to allow us to read contents of files, or in our case, the image which is stored on the user's computer. This is going to allow us to use the file uploader, and this is the input which we added in the HTML. We can then select an image and then set this as our image source. The first step for this to happen is to go with our index and inside here if we take a look for our uploader, this has the ID of uploader. We're going to use getElementById to select this input, and then trigger a function when this is changed. Back to our scripts at the bottom, we can create a reference to this input called imageLoader, grab the ID with getElementById, and the ID was uploader. We can then select our constant of imageLoader and add an EventListener. The event we want to listen out for is the change event, and this will occur when a new file has been uploaded. When this happens, we are going to create a function called uploadImage. Then let's create this function just above, which was uploadImage. This uploadImage is also going to get past the event information since we're using a input. To get started in this function, we're going to do a console log and simply output the value of our file reader. Let's output our reader, all to the browser, right-click and inspect, and we can see what data is passed in the console. Choose our file, select any image, and then here we can see the output of our file reader. Currently, all of our values including the result, is set to a value of null. This is because although we have a file reader object setup, we have not yet passed it our image data. The file data comes from our image uploader, which is stored inside of this e variable. Now let's take a look at the value of e, reload the browser, and we can select a new image, open this up, this is all of the information which is passed to this function about our change event. If we then open up the target, which is our input, click on the arrow, and then scroll down, we have this value called files. This is a list of all the files which has been uploaded from our file uploader. Of course, we have only allowed a single file to be uploaded. So this is just going to have the value of zero. This is our name, which is bridge.jpg. We can now pass this image data to our file reader. Remember we access the event, we then access the targets, we then access the files, and the first file of zero. Back to our function, we can now target our reader, and then we can set this file URL with readAsDataURL. Inside of his method, we then pass in the location of our file, which was e.targets.files, and the first file which is the index of zero. Now let's do a new console log again with the value of reader and see what happens this time. Remember, last time we did this, we got the value of null. So open up the console, select the new file. We have our FileReader object, and now inside of this result at the bottom, we now have some file data rather than the value of null. This FileReader now has all of the data which we need. Now, all we need to do is to access our reader, and then just like we did above with our image, we're also going to trigger a function once this has finished loading. This now leaves us in the same position that we had just above here, where we have our image source, and then we need to load this onto the canvas. To do this, we can move the section just here, paste this inside of our onload function, and now instead of his hard-coded value of bridge.jpg, we're now going to set the image source to be equal to the reader and also access the result value that we've just seen in the console. Now all that's left to do is to save this and test this over in the browser. So we choose a file, grab any image, and this file is now displayed inside the canvas. Hopefully, this is now all working for you too. It is quite a bit going on here, so let's do a quick recap. If we go back to our script. First, we grabbed our file input and stored this inside of a constant called imageLoader. Add all this way and listen for any changes which occurred once a new file has been uploaded. This is then going to trigger our uploadImage function, which we set just here. We created a reader variable which is equal to a new FileReader object. This file reader allows us to read the contents of any uploaded file, which is images in our case. Once this uploadImage function has run, it will then get pass the event information, which contains the image the user has uploaded. This file information is then passed to our FileReader, and we do this with a method called readAsDataURL. Finally, when all of this has finished and fully loaded, we then going to set the image source and then display this onto the canvas with our images. Now uploading. Next, we're going to learn about how to access all the pixels which make up these images. Once we then understand about how all pixels make up an image, we can then play around with them to create our effects. 6. Understanding Pixel Data: To understand how to manipulate our images and also how to add effects, first we need to understand how pixels make up our images. To get the pixel data from our canvas, we have a method available called getImageData. Let's take a look at how we can use this inside of our script. Install this inside of a constant called ImageData. I'm going to set this equal to ctx, and then call the method which we just mentioned, which was getImageData. GetImageData is going to allow us to grab all the pixels which you stored on the canvas. Because we want to grab all of the pixel values from the full size of the canvas, the first two values we're going to add is the starting position of the top left, which is 0, 0. The next two values, we want to grab the full width of the canvas, and also the full height. We can do this with canvas.width and also selecting the canvas.height. This is going to grab all the image data from the top-left right across the page to the bottom-right. Just also as a side note, we can select a smaller part of the canvas if we only wanted the image data for a particular part. We want the full size of the canvas however, since the image is going to be the full size of the canvas. Let's do a console log and see what happens in the browser. Log our imageData, right-click and inspect. Look on the console tab. We now have this image data. Remember from early on we mentioned that the default width and height of the canvas is 150 by 300. We also have this data and if we click on the drop-down arrow, we see we have a 180,000 different values. All of our data is stored in an array like structure. Have 180,000 values, which makes up all of our canvas data. If we click on the drop-down to expand any of these sections, we see all of the values is set to zero. This is because we currently don't have anything stored on the canvas. Now, if we want to see this in more detail with an image, we can grab these two lines of code and place this inside of our own load function. This means that this section will only run once an image has been uploaded. Choose the file, select the image. Our image data is now once again returned. This time though we see a different height and a different width since we set the overall canvas size to be equal to our image. We also see now we have a larger canvas. We now have 4.3 million pieces of data. This next part is really important to understand. First of all, if we grab our height and our width, we can multiply these two values together, so 853, and then multiply this by 1280, which gives us a value of 1.09 million. This would maybe be the number of pixels or the number of pieces of data you would expect to be returned if you multiply the width and the height. However though, we have a value which is four times higher. If we multiply 1091840 by the value of four, we then see 4.3 million, just like in our data. This now leads on to the question of why do we get exactly four times the values back any number of pixels? Well, this is because each pixel on our canvas is made up of four channels. We have a red, green, and blue, and also a alpha value. The red, green, and blue values make up the color of each pixel. So the very first pixel in the top left would be our first piece of data. If we go into here our very first pixel in the top left is these first four values just here. This particular pixel is made up with a red value of 49, green value of 39, and a blue value of 92. The fourth value of 255 is the alpha value, and this is the opacity. If this was a value of zero, this will be fully transparent. But 255 is the highest value, meaning there is no transparency set on this particular pixel. The same, if we go to the next batch of four pixels, you see the red, green, and blue values and also the final alpha value. Our first pixel and our second pixel is the same colors. If we go to the third batch, so 8, 9, 10, 11, we see that because this is blending to a different color, the red value has gone up from 49 to 50, the green value has switched from 39 to 40, and also the blue value has increased too. Just to recap, we have the image data which has been returned from the canvas. We have the height and the width of the canvas and if we multiply these two values, this gives us the total number of pixels on the canvas. Each single pixel has the four values of red, green, blue, and alpha. Which is why the pieces of data which we get returned back to us are exactly four times the amount of pixels. Now with this knowledge of how pixels are made up using the four channels, we will now use what we have learned in the next video, by looping through these pixels and changing them to be different values. 7. Looping Through Image Data: Now we know that everything which is on the canvas or all of our pixels, are now stored in this constant called imageData. We can now use this to loop through all of our data, which is stored inside, and then we can play around with the pixel values. To do this, we're going to create a function, where we can grab this pixel data and have a little play around with each of the values. So I function, and I what to call this change. We can also remove our console log from above. We can grab this line of code just here. Put this out and paste this inside of our change function. All of our pixel data inside this variable is stored in this data property. So we can access this and create new constant called data, and set this equal to imageData.data, and this will give us access to all of the pixel values inside of this data property. So we know there is hundreds, thousands, or even millions of pieces of data inside of this property. So the best thing we can do is to loop through each one of these in batches of four. If we loop through this in batches of four, we know that the first value in each loop is always going to be the red value. The second value is always going to be the green, and the third value is always going to be the blue value. So to do this inside of our change function we're going to create a for-loop. Once the loop runs, we'll create a new variable called i, and initially set this to be 0. We want this for-loop to keep running as long as there's values stored inside of our data. So we'll keep this going as long as i is less than data.length. So data is all of our image data and length is the number of items, so our loop will keep running as long as there's pixel data to loop through. The third statement we're going to say i plus equals 4. So on the very first loop, we'll set the variable of i to be equal to 0, and then for each loop after we'll increment this value by four. We do this because as we already know, each pixel has four values. So increasing this by four on each loop will be the beginning of each set of pixel data. On the very first loop we'll grab the first four pixel values. This will be these ones just here. We can access these with data, and just like an array, we can access the very first one, which is the red value, we did data i. Remember at the very beginning, i is equal to 0, so this will be exactly the same as data 0. If we duplicate this two more times, we can get the second value with the index number of one. This is the value of green, and the blue value with the number of two. If we wanted to, we could also grab the Alpha or the transparency value, but we don't need this for this example. This is the first batch or the first four values. Once this loop has run, the value of i will be incremented by four, and then this will move on to the next set of four values, leaving i to be equal to 4, 5, 6, and 7. Therefore, rather than having these hardcoded values, we can set this to be equal to i, which is the first of each set of four, and i plus 1, and then i plus 2. This first line here is always going to be equal to a red value. This is always going to be equal to our green values, and this is always going to be equal to our blue values. So if we want to play around with these colors, an RGB value goes from zero right through to 255. So for example, we could set the red value to be equal to 255. To see these changes, we now need to apply these pixels back onto the canvas. To do this, we can use a method called putImageData. So just after our for-loop, we can again access our context, and then the method called putImageData. The data we want to put back onto the canvas is this imageData. I'm going to apply this at the very top left to the canvas with the position of 0, 0. Then finally, lets call this change function, we need to add a click handler to our first button. Inside of our index, we'll start with the greyscale button, which is the first button in this effect section. Let's grab this Word documents and this time we'll use querySelectorAll. This is going to grab all of the elements on our page, which has the type of button. Because we have multiple buttons, we then need to select our first button with the index position of zero. Using addEventListener, we can then listen out for any click events, which are then going to run our change function. Let's try this out over in the browser. Lets restart our live server, choose new image. Then if we click on our first button, which is the greyscale, we then set all of the red values inside of our image data to be a strong red value of 255. Let's now update our for-loop, and we'll reinstate our red colors to be exactly how they are in the image. Go down to our green section, where we'll instead set the green to be 255. Upload this image, click on our function and we now see the green color take an effect. We could also do the same to the third or the blue value too. This is all we need to do to apply effects to our images. Now it's just the case of adjusting the color values of our pixels depending on which effects we want to apply, and this is what we're going to begin to do next when we apply a greyscale effect. 8. Greyscale, Sepia & Invert Functions: With the knowledge we now have over just in that pixel values, we can now add some effects and link them to our buttons. The first thing we're going to do is begin with our grayscale button. So we can change this example function to grayscale. With this, we also need to modify our click listener, from change, this also needs to be our function name of grayscale. For this grayscale effect, we need to create a color of gray and then add this to each one of our red, green, and blue values. Inside of our loop, we're going to create a constant for our gray value. Then we need to create our gray value. We're going to do this by, first of all, selecting our red color, which is data i. We're going to add this to our green, which is data i plus 1. Then we add these to our blue, which is data i plus 2. All we're doing here is simply add in together all three of our colors for each pixel on the screen. To reduce this to be a shade of gray, we also need to manipulate these three values. So the red value, we need to multiply this by 0.21, the green color which is in the middle, multiply this by 0.71 and the blue is multiplied by 0.07. Now there's no hard and fast rule we need to use for this gray color. This is simply a formula which are found when researching the subject. We can use any different values inside here. Now we can grab our gray value and set this as our red, also as our green, and also as our blue values. Let's test this out over in the browser. We can refresh, choose a new image. Let's try our grayscale effects. Good, our grayscale is now working and next week we'll move on to the sepia effect, which is basically a warmer version of a grayscale image. All of these functionality is going to be similar, so we can copy our grayscale function, and add this just below. This one is called sepia. We still grab in all of the image data, but this time we need to manipulate this in a slightly different way. So we're going to use the base gray color from the grayscale function, but instead we're going to add some extra red and green values. So for the red value, which is first, we can add 95, a green value, we're going to add 58, and this will give our image a slightly warmer tone. We can then call this function by our second button. Let's copy this, querySelectorAll and then we can select our second button with the index number of 1, the function is sepia. Let's try this out. View as an image and click on the button. This gives us this warmer version of our grayscale image. Next we have the invert function, so we'll copy the sepia function. Add this just below. This one is our invert function. Under the invert effect is also known as a reversed image. The colors are reversed, for example, a black will become white and so on. This will give us a similar effect to old style photo negatives, which we used to get when developing photos. For invert, we don't need to use this gray section, so we can delete this line here, instead, we need to deduct the value of 255 from each one of our colors. The reason we do this is because an RGB value will go from 0-255. If we deduct 255, this will give us the opposite effect. For data i, which is red and deduct the data i. Green value, we do exactly the same, this is 255, and then deduct data i plus 1. The blue, this is 255, and then deduct data i plus 2. We then color this with our button and this button is position 2, and the function name is invert. Let's try this one out. Here's the file. This one is now working too. Now, we have our first three buttons now hooked up, we're going to now move on to the next video, where we'll then swap around all the pixel values to give us our final four effects. 9. Adding Additional Effects: The next file functions which we're going to add, are just going to be a case of switching around our red, blue, and green values. We'll start with change in our red, green and blue values to be the red, blue, and green. Let's grab our last function and we can duplicate this just below. The function name is going to be rbg. What we want to do here is to switch the red, green and blue to then be red, blue and then green. For this one, the red is staying the same all we need to do is to set the first value to be equal to red, which is data[i]. The second value which is just here, this one is going to be equal to blue. Blue is our third value of i plus 2, let's change this. Then our third value is going to be green, which is i plus 1. This is our free colors now switched out. However, though with this function, there is one small problem. We set the red value to be equal to the red value, which is completely fine. We then set any green value to be equal to blue, which is fine too. However, though we've now reassigned the screen value to be a different color. Now, when we try to assign this green color at the very end here, this is now being replaced. This means it's not the original green color for every loop after our first one. If we're overriding any of these values and then reusing them, we then need to store the original color inside of a variable. We'll set a const, and this is our green value. Set this equal to data i plus 1. This is always going to be the original green value. Therefore, when we obtain this is going to change. But we can also access the original green value after we've changed this too. Just to recap, when we loop through all of our pixels, we're overriding our green value with this blue. Therefore, when we try to use this down at the bottom, once again, we'll no longer have the original color. Therefore, we need to store this in a constant just above. Now let's duplicate our click "Listener" let us put in at number 3, any function is rbg. Let's give this a try, chose a new file. Our function is now working. Let's now move on to swap our red, green and blue values with a blue, green, and red, so copy this function. The second one is going to be called bgr. The first color we're replacing our red with the blue value. This is data i plus 2. The second value is going to be green, and this is i plus one. The third value is our color of red, which is data i. But, just like above, we're replacing our data i value with a different color. Therefore, we can store our original data i inside of a variable called red and set this as our third value. Link this to our button. This one is button number 4. The function name of bgr. Let's try this one out. The bgr color is also working too. We have two more, the next one is gbr, so copy our last function. We name this, the first one we need to change is our green color. We need to set i plus 1. The second value is blue, which is our i plus 2. The third one is our red value, which is data[i]. Just like with the loss function, we're overriding data[i]. We can make use of this red constant and update this as our third value. We can link this to our button, which is button number 5, and the function name of gbr. Let's try this one, choose our file. This one is now working too which moves us on to the very last button, which is to replace our red, green, and blue values with green, red and blue. Duplicates our function called grb. The first value is green, and this is currently set, so that's fine. The second value of red is data[i] and since we're updating this during the loop, we can also make use of the original red color, which is stored in this constant. The last value is staying exactly the same. This is also blue 2. This is data i plus 2. We can link this to our very last button inside of this section and this is button number 6, and the functioning of grb. Over to the browser. Click this button and our last function is now working. This is now all of our image effects now working. To finish off this project in the next video, we're going to set up our clear button to remove any effects and reinstate the original image and also set this up so we can download our photo from the browser. 10. Clear & Download Image: The final steps for this project is to add the functionality to clear any effects from the original image, and also to set up this Download button too. We'll start with the Clear button which is going to remove any of the applied effects and reinstate the original image. Applying this is pretty straightforward. All we're going to do is to write a function which will be triggered when the Clear button is pressed. This will then access the file reader's original results, and then we can set it to be the image source. Let's go back over to our script and let's create a new function called clearChanges. First of all, let's do a console log for our FileReader, and then we can call our function from our Clear button, which is index number 7. Let's try this out. Over in the browser we can go into the Developer tools, into the Console. If we click on the Clear, we now have access to our FileReader. Just like earlier before we set an image, we see the result is set to null. But if we were to upload any image and then click on Clear, we then get a new FileReader results with the results of our image. We can now access this FileReader.result, and then set the image source. Let's remove the console log. We can then access our image variable, and set the source to be equal to the reader.result. Let's try this out. The first thing we need to do is to apply any effect such as invert. Clear this, and we now have access to the original image. Finally, we also have the Download button, which is going to allow the user to download the image after they've placed any effects. Over to our script, we can create this as a function called download. Then inside here we're going to create a constant to store our image. We crop the image which you want from the canvas, and then use a method called toDataURL. ToDataURL will return the URL of our canvas image in a default PNG image format. If we wanted this in a different format, we could change this to be image.jpeg. If browser support allows, we can also use WebP2. I'm just going to consider this as the default PNG, and as mentioned before, this toDataURL will return the image URL. How do we actually go about downloading this image? Well, we can download an image URL with a link. We can create a link using the a element, and the way we do this is document.createElement, which will create a link for us, and we can create our link inside here, which is a a element. Store this inside of a constant called link. Just like any regular HTML link, we can also access this, and set the href. The href is the URL which we're going to link to, and we already have our URL just above stored inside of this image variable. Next, we're also going to access our link, and add the download attribute, setting this to equal to be image.png. This download attributes which we just added to our link will specify that the target will be downloaded when the user clicks on this link. This means when a user clicks on this link, it will download whatever is set to the href, which is our image. What we've effectively done now is created a fake HTML link element, which we've not displayed in the browser. This means because the link is not displaying in the browser, we can't click on it in the usual way to download this image. Instead, we can simulate a mouse click on an element by using the click method. To access our will link elements, call the click method, and let's link this download function with our button. This is button number 8, which will trigger our download method and we can select the image to test this out. Choose any of these effects, click on Download. There seems to be an issue, so let's go into the console, we can right-click and inspect. We'll see canvas.toDataURL is not a function, so let's go to our download function. I think we just need changes to be capital letters for URL. Let's try this. Choose a file. Click on the Download, and our image is now downloaded. This now leaves us with a working Clear and Download button. Thank you for taking this project, and I will see you in the next one. 11. Follow Me On Skillshare!: A huge congratulations from me for reaching the end of this class. I hope you really enjoyed it and gained some knowledge from it. If you've enjoyed this class, make sure you check out the rest of my classes here on Skillshare, and also follow me for any updates and also to be informed of any new classes as they become available. So thank you once again, good luck, and hopefully I'll see you again in a future class.