I'm using some images as background, and for retina display they are 640x960 pixels and saved as PNG.
Becasue they eat-up so much memory, I've saved them as RGB-565 (2 bytes per pixel, 5 pixels for red and blue, 6 pixels for green, no transparency), but the memory allocated is the same.
Is the UIImage class aware of those specific formats ?
For the memory usage, I think UIImage think is a RGBA8888 (4 bytes per pixel, 8 bits per channel).
thanks,
r.
UIImages contain some nifty optimization strategies. One of them is probably converting an image to the native format (ARGB32 or something, I forget...) for faster rendering at run-time. At other times, it might choose to keep the image in its original PNG compressed form.
Ah see: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIImage_Class/Reference/Reference.html says "Windows Bitmap Format (BMP) files that are formatted as RGB-565 are converted to ARGB-1555 when they are loaded.". The same will probably hold for your images.
Related
I'm loading a UIImage from NSData with the following code
var image = UIImage(data: data!)
However, there is a weird behavior.
At first, I used png data, and the NSData was about 80kB each.
When I set UIImage with the data, the UIImage took up 128kb each.
(Checked with Allocation instrument, the size of ImageIO_PNG_Data)
Then I changed to use jpeg instead, and the NSData became about 7kb each.
But still, the UIImage is 128kb each, so when displaying the image I get no memory advantage! (The NSData reduced to 80kb -> 7kb and still the UIImage takes up the same amount of memory)
It is weird, why the UIImage should take up 128kb when the original data is just 7kb?
Can I reduce this memory usage by UIImage without shrinking the size of the UIImage itself??
Note that I'm not dealing with high resolution image so resizing the image is not an option (The NSData is already 7kb!!)
Any help will be appreciated.
Thanks!!
When you access the NSData, it is often compressed (with either PNG or JPEG). When you use the UIImage, there is an uncompressed pixel buffer which is often 4 bytes per pixel (one byte for red, green, blue, and alpha, respectively). There are other formats, but it illustrates the basic idea, that the JPEG or PNG representations can be compressed, when you start using an image, it is uncompressed.
In your conclusion, you say that resizing not an option and that the NSData is already 7kb. I would suggest that resizing should be considered if the resolution of the image is greater than the resolution (the points of the bounds/frame times the scale of the device) of the UIImageView in which you're using it. The question of whether to resize is not a function of the size of the NSData, but rather the resolution of the view. So, if you have a 1000x1000 pixel image that you're using in a small thumbview in a table view, then regardless of how small the JPEG representation is, you should definitely resize the image.
This is normal. When the image is stored as NSData, it is compressed (usually using PNG or JPG compression). When it's a UIImage, the image is decompressed, which allows it to be drawn quickly on the screen.
In my app, I convert and process images.
from colour to greyscale, then doing operations such as histogram-equalisation, filtering, etc.
that part works fine.
my UIImage display correctly, I also save them to jpeg files and it works.
The only problem is that, although my images are now greyscales, they are still saved as RGB jpegs. that is the red, green and blue value for each pixel are the same but it still waste space to keep the duplicated value, making the file size higher than it could be.
So when i open the image file in photoshop, it is black & white but when I check "Photoshop > Image > Mode", it still says "RGB" instead of "Greyscale".
Anyone know how to tell iOS that the UIImageJPEGRepresentation call should create data with one channel per pixel instead of 4?
Thanks in advance.
You should do an explicit conversion of your image using CGColorSpaceCreateDeviceGray() as color space which is 8 bits per component, 1 channel.
I have the following issue:
I have a primary view object (that inherits from UIView) that displays a grid of 16 squares (each is a class I created that inherits from UIImageView), in a 4x4 layout.
Each of these 16 squares is 160x160, and contains an image (a different image for each square) that is no bigger than 30kb. The image, however, is 500x500 (because it is used elsewhere in the program, in its full size), so it gets resized in the "square" class to 160x160, by the setFrame method.
By looking at the memory management feature of Xcode when the app is running, I've noticed a few things:
each of these squares, when added to the primary view object, increase the memory usage of the app by 1MB. This doesn't happen at instantiation, but only when they are added by [self addSubview:square] at the primary view object.
if I use the same image for all the squares, the memory increase is
minimal. If I initialize the square objects without any images, then
the increase is basically zero.
the same app, when running in the simulator, uses 1/6 of the memory
it does on an actual device.
The whole point here is: why is each of the squares using up 1MB of memory when loading a 30kb image? Is there a way to reduce this? I've tried creating the images in a number of different ways: [UIImage imageNamed:img], [UIImage imageWithContentsFromFile:path], [UIImage imageWithData:imgData scale:scale], as well as not resizing the frame.
When you use a 500x500 image in a smaller UIImageView, it's still loading the larger image into memory. You can solve this by resizing the UIImage, itself (not just adjusting the frame of the UIImageView), making a 160x160 image, and use that image in your view. See this answer for some code to resize the image, which can then be invoked as follows:
UIImage *smallImage = [image scaleImageToSizeAspectFill:CGSizeMake(160, 160)];
You might even want to save the resized image, so you're not constantly encumbering yourself with the computational overhead of creating the smaller images every time, e.g.:
NSData *data = UIImagePNGRepresentation(smallImage);
[data writeToFile:path atomically:YES];
You can then load that PNG file corresponding to your small image in future invocations of the view.
In answer to your question why it takes up so much memory, it's because while the image is probably stored as a compressed JPG or PNG in persistent storage, I suspect in memory it's held as an uncompressed bitmap. There are many internal formats, but a common one is a 32-bit format with 8 bits each for red, green, blue, and alpha. Regardless of the specifics, you can quickly see how a 500 x 500 pixel representation, with 4 bytes per pixel could translate to a 1 mb of memory. But a 160 x 160 image should be roughly one tenth the size.
I want to display a page containing about 6000 tiny image thumbnails (40x40 each). To avoid having to make 6000 HTTP requests, I am exploring CSS sprites, i.e. concatenating all these thumbnails into one long strip and using CSS to crop the required images out. Unfortunately, I have discovered that JPEG files cannot be larger than 65500 pixels in any one dimension. Wary of further limits in the web stack, I am wondering: are any of the following unable to cope with an image with dimensions of 40x240000?
Internet Explorer
Opera
WebKit
Any CSS spec
Any HTML spec
The PNG spec
Edit: the purpose of this is simply to display an entire image collection at once, requiring that the user at most has to scroll. I want the "micro-thumbnails" to flow into an existing CSS layout, so I can't just use a big rectangular image. I don't want the user to have to click through multiple pages to see everything. The total number of pixels is not that great - only twice what would fit on a 2560x1600 display. The total file size of all the micro-thumbnails is only a couple of megabytes. Assuming every image is manipulated uncompressed in the browser's memory, taking 8 bytes of storage per pixel (RGBA plus 100% overhead fudge factor), we are talking RAM usage in the low hundreds of megabytes; not unreasonable for a specialized application in the year 2010. The only unreasonable thing is the volume of HTTP requests that would be generated if all micro-thumbnails were sent individually.
Well, Safari/iOS lists these limits:
The maximum size for decoded GIF, PNG, and TIFF images is 3 megapixels.
That is, ensure that width * height ≤ 3 * 1024 * 1024. Note that the decoded size is far larger than the encoded size of an image.
The maximum decoded image size for JPEG is 32 megapixels using subsampling.
JPEG images can be up to 32 megapixels due to subsampling, which allows JPEG images to decode to a size that has one sixteenth the number of pixels. JPEG images larger than 2 megapixels are subsampled—that is, decoded to a reduced size. JPEG subsampling allows the user to view images from the latest digital cameras.
Individual resource files must be less than 10 MB.
This limit applies to HTML, CSS, JavaScript, or nonstreamed media.
http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/CreatingContentforSafarioniPhone/CreatingContentforSafarioniPhone.html
Based on your update, I'd still really recommend not using this approach. Don't you think there's a reason that Google's image search doesn't work like this?
As such, I'd recommend simply loading images as required via Ajax. (i.e.: When the user scrolls below the currently visible set of images.) Whilst this will use more connections, it'll mean that you can have sensibly sized thumbnails and as a general approach is much more manageable than having to re-generate pre-generated thumbnail image "sheets" on the back-end when a new image is added, etc.
This question already has answers here:
What are the different usecases of PNG vs. GIF vs. JPEG vs. SVG? [closed]
(14 answers)
Closed 9 years ago.
I'm using ImageMagick to convert some files from one format to another. I was always under the impression that .png files were supposed to be as big/small as .jpg if not smaller, and definitely smaller than .gif.
However when I run
convert photo.jpg photo.png
The files I'm getting out is about 6 times bigger than the original jpg.
Original jpg is a regular photo about 300x500 px, 52 kb. Output is a proper png of the same dimensions, but size is about 307 kb?
Does anyoone know what the hack is going on? Am I doing something wrong?
P.S.:
I tried both on Debian and Windows with the same results.
P.P.S.:
Also when I add resize option to this and resize to 10000 x 10000. Converting and resizing to jpg takes a few seconds, but it works, if I do the same of png, I jsut strt running out of memory altogether
P.P.P.S.:
For people who keep marking this question as duplicate of PNG vs. GIF vs. JPEG vs. SVG - When best to use? . Please read carefully and understand the question. It's not a duplicate, since this question asks' about files produced programmatically with specific application (image magick). The question you marking as duplicate, is asking which image format is better to use on the web. Two DIFFERENT questions.
The key thing to note here is that each image file format is best for specific purposes.
JPEG stands for “Joint Photographic Experts Group.” That right there should tell you that the .JPG file format is optimized for photographs. It doesn’t work so well for line-art, logos, gradient or tiled / patterned backgrounds, and the like. .JPG’s DCT (Discreet Cosine Transform) artifacts (the “blocky” artifacts we all know and loathe) are much more noticeable with line art and logos than with photos.
PNG has replaced GIF for everything that GIF was ever good for, except one, and that only because no clear standard has emerged: animations. Animated .GIFs are well known on the Web. There are two competing standards for animated .PNGs: APNG and MNG.
APNG is supported in most modern browsers, and is also fully backwards compatible (the file extension is .PNG, not .APNG, and if any program that can display .PNGs but doesn’t know APNG is “fed” an APNG, it will display either a stand-in image of the developer’s choice, or the first frame of the animation if no such stand-in was provided — as far as the older program is concerned, it’s just an ordinary single-frame .PNG with that one image in it — the rest is safely ignored). Gecko (FF, etc.) and Presto (Opera) support it natively, and Google Chrome (using Webkit) can with an add-on.
MNG has the backing of the actual PNG-format development team, but is its own format and is not backwards compatible, but is more powerful and flexible. Right now, only KHTML-based browsers (Konquerer) support it: not Trident (IE), Gecko, Webkit (Chrome, Chromium, Safari), nor Presto.
PNG does everything (except animations unless enhanced with APNG) that GIF does, and better. All else being equal, a .PNG will almost always be smaller than a .GIF at the same resolution and bit depth. Like .GIF, .PNG can support color depths up to 8 bits per pixel in indexed-color (paletted) mode, but unlike .GIF (yet like .JPEG) it also supports direct-color mode at 24 bits per pixel.
In either mode it can add 8 bits of alpha transparency, unlike .GIF (which can only do indexed color transparency [pick a color out of the palette to be replaced with 100% transparency, aka invisibility] — .PNG can do that, too). Alpha transparency produces much better results than indexed transparency, because the pixels can be partially transparent, whereas with indexed transparency (the only kind available in .GIF) your choices are either opaque or invisible. This makes for “halos” around non-rectangular objects when placed against background colors other than the one the .GIF or indexed .PNG was originally “matted” against. It also inhibits being able to do effects such as glows, drop shadows, and, of course, see-through colored objects (without dithering). Alpha transparency can do all of those things with ease, against almost any background (glows would be largely invisible on a white background, and drop shadows would be invisible on black, but you know what I mean).
Yes, you can do 8-bit alpha transparency in an indexed-color .PNG! And guess what? Even Microsoft Internet Explorer 6 can display those just fine, complete with transparency! It’s only the 32-bit .PNGs (24-bit RGB color + 8-bit alpha) that IE6 choked on and displayed as gray!
The most well-known program that can export PNG8 (indexed color) with alpha transparency is Adobe (formerly Macromedia) Fireworks. The Photoshop “Save for Web and Devices” (at least as of CS3) could not do that, despite having basically lifted the feature from Fireworks when Adobe bought out Macromedia. It can save PNG8, but only with indexed-color transparency.
Anyway, full 32-bit (or even 24-bit) PNGs will be pretty large, though usually much smaller than the nearest equivalent .BMP or .TGA or uncompressed .TIFF or some such (unless you’re trying to do a photograph with it — that’s what JPEG is for!). It will usually be somewhat smaller even than .RLE (losslessly compressed .BMP) or losslessly compressed .TIF, all else being equal.
Unlike most of these other formats, PNG also supports 48-bit RGB color, with optional 16 bits of alpha transparency, for extremely high quality (much higher than most monitors can display). These are best used as an intermediate storage format, to retain information from a high bit depth scanner or camera (RAW mode) or some such. Their file sizes would be quite large, despite the lossless compression.
One thing that .PNG cannot currently do is handle non-RGB color spaces such as CMYK or L*a*b.
In short:
For photographs, use .JPG.
For line art and logos of limited color, use indexed-color .PNG (PNG8), with alpha transparency if needed.
For line art and logos of extensive color (e.g. lots of gradient fills, metallic chrome-type reflection effects, etc.), use direct-color .PNG (PNG24) with alpha if needed, if you want the best quality or need transparency (and don’t mind it not working in IE6 or use one of a variety of IE6 workarounds for transparent PNGs), and don’t mind the larger files and bandwidth usage. Otherwise, use .JPG, but be aware that the quality will be degraded. You may need to crank the JPEG quality up pretty high, especially for logos or other graphics with “text” in them, which would reduce your file size savings.
For non-Flash/Silverlight/video/HTML5 Canvas animations, .GIF if the main choice at present, but be prepared to switch to APNG (I don’t think MNG is going to beat it, despite the more official support from the JPEG developers).
JPG is a lossy compression algorithm while PNG is a lossless one.
This fact alone will (in general) make JPG images smaller than PNG ones. You can tweak the compression ratios for each format, so it could also be that you're not compressing your PNG files as much as your JPG ones.
For a photographic image saving as JPG will usually produce a smaller file than PNG as there's more noise or randomness in the image for the compression to work with. Images created by graphic art tools will tend to have more hard edges and areas of solid colour which will compress better in PNG.
If you have text in your image then PNG is going to produce a better quality image as the harder edges of the characters won't be blurred like they would be if JPG is used.
GIF is smaller because it's based on an colour palette (of 256 colours) rather than the separate RGB values for each pixel (or group of pixels) in JPG and PNG.
The PNG format can provide images of 24 bits per pixel or 8 bits per pixel. JPG is a 24 bit format, but it uses lossy compression to reduce the file size significantly. PNG and GIF both use lossless compression, but GIF only works with 8 bits so it requires your image to have 256 colors or less - this often results in a grainier picture.
Try the -colors and -dither options in ImageMagick to reduce the number of bits in your PNG output. At that point it should be comparable to the GIF file size. If you need to reduce it further, there are utilities to optimize the PNG.
The .jpeg file format is a lossy format, it throws information away. Which makes for good compression ratios. The .gif file format is not lossy but loses other information, it only supports 256 colors. The .png file format is not lossy and preserves the color range.
It depends on the kind of image. JPEG's lossy compression works very well on images with lots of color gradients (i.e. photos).
Try it on an image consisting of areas with the same color separated by sharp edges (screenshots are good, unless they show a photo desktop background, and the fancy window borders and task bar of Vista and Windows 7 also tend to mess this up). JPEG is bad at that kind of thing, and you'll probably find PNG to compress better (probably better than GIF too).
Replying to :
Does anyone know what the hack is going on? Am I doing something wrong?
yeah I study this, you aren't doing nothing wrong, you produced 8-bit/color RGB PNG
I solve it with reduce or compress png with pngnq ( http://pngnq.sourceforge.net/ ) that produce 8-bit/color colormap PNG.
pngnq seems to me the most improved project, since is a fork of others like pngquant etc, and is normally in main stream of Linux distros so I just do this:
convert photo.jpg png:- | pngnq -s 1 > photo.png
For the last upvoter (2016): pngnq as been deprecated in favor of pngquant (https://github.com/pornel/pngquant)