Calculate thumbnail sizes with RMagick - ruby-on-rails

I'm using attachment_fu and RMagick to upload/resize images on a rails app. Currently I use the local file system as the storage but I have a plan to use AWS S3 for the job. Anyway I am quite interested to know what other peoples' experiences on using S3 and also I have a one big question for you. In my app when a user uploads an image I resize this image to 5 different sizes and store them along with the original images. (altogether 6 images) based on thumbnail sizes provied in the model:
:thumbnails => {
"thumb" => "120x80",
"extra_small"=>"480x320",
"small"=>"640x480",
"medium" => "800x533",
"large"=>"2738x1825",
"extra_large" => "3464x2309"
Finally I get:
image_foo.jpg (Original Image)
image_foo_thumb.jpg
image_foo_extra_small.jpg
image_foo_small.jpg
image_foo_medium.jpg
image_foo_large.jpg
image_foo_extra_large.jpg
The reason why I re-size these images is I need the actual sizes of each image to be stored in the database. But actually even I specified the sizes for thumbnails I don't get the exact sizes. Anyway its OK, as the size is calculated based on the aspect ratio.
But I really don't like to waste the space on the server if I can calculate the thumbnails sizes without saving them to the file system. In other words, I only need to store the original file not the thumbnails, but still I need to get the sizes of the thumbnails. Is it possible to get the actual thumbnail sizes without creating them in RMagick?

Space on S3 is relatively cheap. So I wouldn't worry too much.
However, you could consider converting the images to fewer sizes. You could leave small and extra-small out and use the width and height attributes of the HTML img tag. However, that will make your side load slower and cause more traffic.
I guess what you are really looking for is a solution that converts the files on the fly when they are requested right? I am not sure if there is a solution for that off the shelf. However, this would be a major performance suck.
So my recommendation is to just stick with all the different sizes and pay a few cent more to amazon. This will yield best performance and will be easiest to maintain. You don't have to worry about scaling and the fact that storage is getting cheaper and cheaper works for this solution.

Related

Rails image manipulation

in our website we are retrieving data from an API, which does not pull images bigger than 100 × 75 pixels, then we show them listed. example We need to double up this size to match with our design.
Is there any Gem that does this, without loosing quality and not impacting performance?
There is no way to upscale an image without losing quality - you're basically asking an algorithm to fill in image data that simply does not exist in the file in the first place.
However, depending on the rate of the scaling and the images themselves, you could have acceptable results.
Since you want to do this effectively and there is no benefit of doing the resizing on the server anyway, I'd advise simply using CSS to achieve this on the client side - just set the desired width/height attributes for the specific img elements.
If you really want to do this on the server (e.g. if you need to save the resulting images), one option would be to use the Paperclip gem's image processing capabilities.

Download #2x and #3x images from server to Tableview

I have a tableview that is populated from images on my server that I download. My question is How would I go about getting different images for the different resolutions for the devices? 6 vs 6plus etc?
Do I write code that is device specific? e.g
if device is equal to 6 load #2x images 'from #2x url'
else if
device is equal to 6 plus load #3x images 'from #3x url'
and so on.
Or is there a more efficient way of going about this?
You've got several options, depending on the back-end technology stack you're connecting to.
Options if you're using a custom server that you've built yourself, or have control over the code:
Add device scale detection into your image service that checks the inbound user-agent for device scale, and serves the appropriate image for that device. This is hands down probably the simplest solution to implement if you manage your own back-end.
Write into your API a url path param that serves the appropriate image scale; you can then use the UIScreen class (UIScreen.mainScreen().scale) to adjust your target URL accordingly, e.g.:
https://api.yourbackend.service/images/{imageid}/#2x.jpg
This is arguably more difficult to implement, but it's also a lot more robust (doesn't rely on potentially changing user-agent strings), and it's a lot cleaner when logging or querying analytics.
You could probably also use something like retina.js to handle this on your back-end, though I can't tell you whether or not it will work heedlessly (haven't tried it).
Options if you're using a CDN image host:
Use their built in HiDPI support (Cloudinary, for example, provides this -- read about it here).
If your CDN doesn't support this, switch to one that does ;)
You are coming at this exactly backwards.
A table view cell's image view is tiny. You are not going to be showing these images at full size anyway. So there is no point whatever downloading larger and larger images only to be displayed at tiny sizes. That's a massive waste of time, bandwidth, and ultimately memory (if you really try to display large images in every cell, you will run out of memory and crash).
If you have a choice of image size to be retrieved from the server, you should be doing just the opposite of what you are suggesting: download a thumbnail of your image suitable for display in the table view. If the thumbnail is twice the size of the image view, it will look good at all resolutions with minimal waste of memory.
If this app is about also fetching the real full-sized image, outside your table view, you can do that later when requested by the user.

What are the ways to reduce bundle size on iOS?

I have some images which are huge in size and my bundle size currently is 70 MB. I think Xcode already runs the assets through png crush.
Do not use any text images with useless effects, use UILabels instead.
Draw simple shapes and effects using CAShapeLayers instead of using
images.
Use JPEGs instead of PNGs where you don't need transparency.
(Actually file size depends on the image content here)
Use Save for Web option in PhotoShop or other tools to optimize PNG
images.
Use sprites combined together instead of separate images.
Make sure you delete all unused resources.
Do not localize common parts of the images, localize only the
different parts. (think of a background image with a small flag at
the bottom for each locale. use one single bg image and separate flag
images. localize flag images only, not the entire bg images with the
flags.)
Use the same splash images for iOS7 and previous iOS versions. (You
need to manually edit the JSON file in .xcassets)
Try using a CDN to download assets on the first launch.
In addition to images keep those in mind too:
Try replacing custom fonts with default system fonts if you don't
need them really.
Use MP3 audio files instead of WAV files. (or other
compressed formats)
Make sure you delete all unused 3rd party frameworks.
You can try converting the images to jpg (if they don't have any transparent regions).
Also try using http://imageoptim.com/
It seems very unlikely that you actually need huge images. After all, the screen is not huge. Thus, the most likely form of size reduction is to reduce the physical dimensions of the images to the size you are actually going to be displaying.
This saves bandwidth when the user downloads the image, reduces the size of the app on the user's hard disk (the device), and also saves memory at the time an image is loaded. It is a vast waste of RAM to load an image that is larger than the size at which it will be displayed; after all, remember, the memory involved rises exponentially with the square of the difference.
One option is to host the images on a CDN like OpenText and fetch them as part of app initialization, or whenever they are first needed. Obviously this is more coding, but projects like SDWebImage make it pretty easy:
https://github.com/rs/SDWebImage/tree/master/SDWebImage
It also gives you the flexibility to swap out those images later if you use caching headers.

When to use double size images

I was thinking to write some quiz app where questions are represented as images.
My question is, for each quiz question (question.jpg), and thus a jpg file, do I have to create
a double sized question#2x.jpg file?
Is it necessary?
Doing this seems will increase size of my program so I was thinking when/if this is necessary to do?
PS. And in case I have to do it, I will just have to double in size each image manually and add to the project right (both original and double sized image)?
PPS. Just to add more info. The questions are located on the web site, I have to download them and add to my project manually (like resources). On web site there are no different versions of the same image. So, I have whatever is on the web site. Some images I noticed are 800x600 in dimensions but some are also in dimentions 500x400. So after I download these images, how shall I name them? Just with original names? and forget about the #2x extension? What's the best practice?
(if this will help my image view will probably be smth .like 310 in width). Do I have to modify them in size? What to do?
Apple's naming conventions of high resolution images can be found here:
Apple doc naming conventions
If you are developing in the way that you want to support old screen as well as retina screens. You can use xxxx.jpg for old devices as iPhone 3gs and iPad 1, and use xxxx#2x.jpg for retina displays. Where the aspect ratio needs to be the same but the #2x image needs to be twice as big.
In your case "my image view will probably be smth .like 310 in width", then the #2x image needs to be 620px in width and normal revolution 310px.
There is actually no need to have both image sizes in the app as you can use the same image and just scale it(If you really really need to have the old resolution supported).
Even if you add just a #2x, it will scale itself if someone on an old device installs your app. It may become a bit blurry but will still be quite ok.
If you are planning to use a lot of images in your app I suggest using some sort of web service where the user can download content that is to be shown. But that's just me. As the app will quite quickly become very large as images takes up quite a bit of space. Of course this all comes down to how many images you will have.
The drawback of using a web service is that the user much have an internet connection to be able to play. And download your content.(Most quiz apps I know of does use a web service for this.) This is a matter of taste.
If you do need to support normal and #2x here us a method you can use. This method will return the scaled image so you just need the normal one or the #2x one and then scale to the other size. This will at least help you a bit when it comes to getting either your app size down or your clients download time down.
If you are using .jpg's and scaling them upwards you can quite easily get a pixalated image as it is a lossy format. But if that's what you still want to do and maintain aspect ratio, this is one way to do it:
-(UIImage*)resizeImage: (UIImage *)imageToScale withScale:(CGFloat)theScale{
UIImage *image = [UIImage imageWithCGImage:[imageToScale CGImage]
scale:(imageToScale.scale * theScale)
orientation:(imageToScale.imageOrientation)];
return image;
}
Usage
[self resizeImage:[UIImage imageNamed:#"question.jpg"] withScale:0.5];
0.5 would double the size and 2.0 results in an image half the size as the original.
If you want a more complex method to set for instance set a specific target size just say so and I'll edit this answer.

Carrierwave - Processed image too big in size

I got a Carrierwave uploader and process images like this:
version :thumbnail do
process :resize_to_model
process :quality => 90
end
def resize_to_model
thumbs_size = model.thumbnail_size
resize_to_fill thumbs_size[:width], thumbs_size[:height]
end
However, after processing an image which was 1024x724px and is 214x151px afterwards the file size only went down from 2,1mb to 1,8mb. I think 1,8mb really is a lot for that size. Can I do something about that? Even with 90% quality the image should be like maybe 100kb or not?
Before someone asks, the rest works perfect. No errors, the size in px is right and everything else is also fine.
Edit: I forgot to mention I Use rmagick(resize_to_fill). Is that a reason maybe?
The difference between 100% and 90% quality is so small and the storage space savings is negligible. If you are truly just using this version as a thumbnail you should look at using a much lower quality, say 60% or 40%.
If you are concerned about making sure the quality is still "good enough" then you could also look at different compression techniques. The process used to provide #2x images for Retina displays can be used in this instance. A great resource is available in the Filament Group's article Compressive Images.
The tl;dr version is basically, use the original (or near original) size of the image but drastically reduce the image quality (to 0-20%). Then, when using the reduced quality image be sure to provide width and height attributes in the <img> element to resize it down to the thumbnail size. Because the image will be scaled down you will not see the reduction in quality of the "thumbnail" image.

Resources