[MUSIC] In this lecture we will discuss overall image handling for our entire application as well as this module. We'll cover aspects of content storage. How we're going to scale our images? How we're going to access images of different sizes through queries? How we're going to edit and upload those images from our devices to our website. Before we get in too deep let's talk about some overall usages, of course when the user see application. They're going to see various viewers that are accessing, content that already exists. For example, they'll query various images, they'll get back a URL that tells them where the image exists, there's an example up at the top. And depending on the viewer and depending on its size. It will provide certain requirements as to what size the image you wants to get and will express this in many more sizes. So if I was trying to express a thumbnail it might say width about 75 if it was a full screen viewer it might say about a thousand. You will be able to query our database of image content sizes in order to get the appropriate information. When we go to contribute information, we want to be able to select images. Whether they be from a file system or directly from a camera, we want the user to be able to crop that image and we'll restrict everything to a standard size of about three by two, width by height. Once they are finished selecting their cropped area, then they'll be able to post along with the image. So no longer will we just be Posting a caption will have a required field of content that must come into the API. When the images come in, our controller needs to take care of getting everything scaled and we'll delegate to some image scaling software that'll be able to build sizes. Let's say from thumbnail small, medium, large sizes as well as retain the original. And we'll finish up the module on the UI side by building a viewer that will be able to step through the different images. With that in mind, we have certain aspects to address. We have the concept of storage size. Now the metadata that we've been storing might have taken maybe up to 100 bytes each, and now that we're going to start storing the image content, we could take up to a couple of thousand K to several megabytes. We need to account for that. There's some cardinality. Logically an image has image content, a one-for-one relationship. However, physically in the database, there's a one-to-many because there are different size content in the database that's going to be appropriate for how we're going to be displayed on the individual webpages. We need to be able to upload images to the website, and the source of that image needs to be able to come from a file system or a camera. We need the user to be able to do some minor edits like select the area that they want of the image and crop it appropriately, and some consistency when they edit. So it said at about a 3 to 2 ratio. We're going to do a little bit wider data store. So when it came time to deciding how we're going to store our images, there was some off the shelf products that would have made it really easy to do. Two of them are Paperclip and CarrierWave. You can Google those gems and give a look yourself. But they're basically full featured, and honestly, if we'd had brought those gems in, we pretty much would have been done with half of this module. And an added benefit, they have full integration with the image resizing software we're going to be using called ImageMagick. The downside however is they required file storage and it wasn't easily customizable. Now file storage is fine for developement, but when you deployed a Heroku the Heroku filesystem isn't writable or what is writable isn't persistent. What you can write today won't be there tomorrow. So instead of using some of those off the shelf solutions, we're going to use a more homegrown approach, which is actually quite attractive once you get down to it. We're going to store our metadata in a relational database, so we're going to continue to have images related to things. But then we're going to store the content for that image in Mongo. And we're going to leverage the BSON Binary type, and just go ahead and avoid the complexities of GridFS entirely. Now relational databases do support Blobs but there's an expense to that. The relational database Is more naturally suited for columnar data with relationships, not for content storage. Our images are of a fixed limit. We can keep the below 10 megs easy, and that of course is below the 16 megabyte limit of a Mongo document. So again no real reason for GridFS. We would have a reason to bring GridFS into the picture of we had the risk of having our images above 16 megabytes. And one of the big reasons for bringing in Mongo to store our images is everything to date has been relational in our application. This is a good excuse to bring in Mongo because it's a good option for this kind of storage requirement. And our free mLab account allows for 500MB of storage. With images between let's say a couple of K and 5 megs for the most part. We can store a fair amount of images. Now beware though the actual file size cost to store a 5 meg image is larger in this space than 5 megabytes. But for the most part 50 images or so we'll be okay. So we take a look at our data model for our image and image content, we'll recognize some fields that are very familiar to us, id caption, the creator_id and that information. And all of this is associated with the thing through thing images. But on this side now in the Mongo database we going to start storing any image content with image id, image height. Content type content and something that tell us whether it's the original or not. And we will store many of this per image and it is perceived to be that when we do have many of this that there will be of a different width and height, but of the same image. Copies of the same image. And when we make copies of the same image, we're talking about scaling that image. There were two primary options. One was ImageMagick, it's very popular. If you start asking about rails and image scaling, this is going to pop up really quick. Another one that's mentioned a fair amount is GraphicsMagick. And it's a fork from ImageMagick in the early 2000s and it claims to be a smaller footprint, and probably something that deserved a little bit more serious look into than I gave it. But I found that just ImageMagick just worked and there was no reason to go back. Both are available in Heroku, ImageMagick, pretty much out of the box. I think there's a little extra configuration you need in order to get GrpahicMagick working. But one thing to note, it required ImageMagick 6, which is on Heroku but on your local development environment, the current version is 7. So it may require a little bit of extra attention or work in order to make the installation locally, not 7 but ImageMagick 6. However, are needs are pretty modest. All we're looking for is some scaling and some watermarking for test images. If you can't get ImageMagick 6 installed locally, don't sweat it too bad. All interactions with ImageMagick is within the class, within the method. If you can't get ImageMagick installed and talk to it natively in your development environment just develop a stub, a lie. You're handed an image and with a request to resize it. You look for an environment variable that says am I in a supported environment? No I am not. And you hand it back and you say here it is. Or you hand back a fake image. That is of the size they're asking for, okay? But it is nice if you can get it all installed. Now to talk to ImageMagick, we had some options. RMagick is more like the Cadillac of interfacing with ImageMagick. It's a library interface. MiniMagick, the one that we've chosen is more of a just a command line wrapper. And then yes ImageMagick did change they're command line between 6 and 7, which is one of the major things that I'm saying that you need 6 and not 7. Now MiniMagick will also work with GraphicsMagick and thus the cycle could continue. Now once we have these images in the database at different sizes clients are going to want to come to us and say I'm trying to display a list of thumbnails. I'm trying to put up a medium size image somewhere on my page or I'm doing a full page viewer. They're going to be making queries using an API call that tells us what image they're looking for, the content for that image and what their minimal size requirements are. So we're going to find them the image that either matches those specifications or one higher, and these can be incomplete. If they can specify width, they could specify height, they can specify width and height. And when they go to download, there's no authorization checks. We just chose to do it that way. If you have a URL for an image, you'll be able to download that without any additional checks. That will actually be convenient from an authentication standpoint. So when an image comes in and we want to know what size it is, this is especially useful for the original image, we want to leverage the EXIF Reader. And we're going to limit our support to just JPEGs for this application. It can read JPEG images and be able to tell us what the width and the height is at a minimum. We won't be using any of the geolocation capabilities within the sizing. We're going to rely on the user to supply where that image is. And the user may supply that information with a street address, or lat and long, or whatever we can get from them. On the web client side we're going to need to be able to upload the image whether from the file system or the camera if we're on a mobile phone. And we're going to need to edit this image in a minor way. We're just going to need cropping. There are many solutions and not all of them are available in railassets.org many more than what was selected was full featured. But again, all we really needed was a cropping solution. And two of them had strong evidence of working right out of the box with our file upload capability of ng-file-upload. The first is ngImgCrop. However, that seems like it's more end of life. It only supported square sizes and it really hasn't been updated in a couple years. There was a fork of that at ngImgCropFullExtend, which we are using. And that supported rectangular 3x2 views. However, I did notice that after I started using it in September of 2016 that in October it moved to a new name, uiCropper, same library but all updates are under the new name. In summary, we're going to be storing content for images. We're going to be able to query for that content based on sizing. And then on the web client side, we're going to be able to select, crop and upload content for an image. And we're going to look to view that in a responsive viewer. We can build something kind of nice in Angular. What's next? Image content And the BSON Binary type. Let's start by building a model class to track our image content and gain a little practice and insight into the BSON Binary type and how we can use that to store our data.