So I am using Dart's image package to manipulate an JPG image which was loaded and decoded.
Filtering the image works perfectly fine, however, display the image seems to be somewhat slow.
The idea was to use Flutter's Image widget in combination with a MemoryImage a la:
Image.memory(bytes)
bytes must be a binary representation of the image, e.g., PNG, JPG etc. and is not compatible with the image library's internal uint32 storage format or a simple bitmap. As a result, one is required to encode the bitmap back to a JPG which is pretty slow.
Is there a more efficient way of doing this?
Related
I am trying to understand the basics behind Pixbuf and its factory methods new_from_data and new_from_stream.
new_from_data requires a string of bytes containing the image data, and other information such as bits per sample, with and height of image.
What I don't understand is why new_from_stream does not require those additional image information. Then, how can the Pixbuf know how to render the image new_from_stream does not provide any additional information other than the Gio.InputStream ?
new_from_stream() expects to get a stream of a supported image file, equivalent to new_from_file(). All the image formats contain metadata like height and width.
new_from_data() on the other hand expects a pixel buffer, which is essentially just an array of pixels without any metadata.
We all know that converting from jpg to jpg makes an image lose quality, and that the same doesn't happen when it's png to png, but what about jpg to png ?
In my mind it makes sense that it doesn't, but still I'm not sure.
I think that good answer to this question probably would be an article in which there would be a good explanation of why it happens or not. Do you now of any ? I couldn't find such article.
It doesn't, but it's complicated.
Reading of JPEG is not a precisely defined process. Different JPEG decoders are allowed to produce slightly different results from the same file.
Converting JPEG to PNG makes pixels forever represent the particular method that was used to decode the JPEG, even if it wasn't the best one. If you use a "bad" JPEG decoder for the conversion you lose ability to use a "better" JPEG decoder later.
The differences are:
Chroma upsampling. JPEG may store chroma (~color) at lower resolution than luma (~brightness) of the image. The spec doesn't say how the chroma channel should be resized, so some decoders use blocky nearest-neighbor scaling, some use bilinear scaling, some do even weirder things.
Numeric precision. JPEG requires calculations to be done to convert image from DCT and YCbCr representation to RGB. This can be done quickly and cheaply using integer math and 8-bit color, or a tiny bit better using floating-point math and higher-depth color.
Color profiles and CMYK. Conversion may change color space (in case of CMYK it has to convert to RGB), which is easy to get wrong.
There are other reasons to avoid the conversion:
The file will almost certainly become much larger. JPEG compression artifacts are the worst case for PNG.
The file will lose metadata (like camera info, GPS). While in theory PNG could carry the same metadata, in practice converters rarely preserve it.
And a case for conversion: jpeg2png project, which doesn't merely convert the file, but also uses quite advanced post-processing to smooth out JPEG compression distortions. In that case you might salvage a low-quality blocky JPEG and get a smoother image instead.
The process you describe is:
JPEG Stream => JPEG DECODER => BITMAP
=> PNG ENCODER => PNG Stream
There is no change in step #2. Step #1 might have rounding errors inherent in JPEG.
The image at the end of this question is a PNG with mode I, which stands for Indexed, as far as I can tell.
I'm trying to create a thumbnail out of it, and save it as JPG with PIL.
However, is I leave the mode alone, PIL won't let me resize it with error unable to generate thumbnail: cannot write mode I as JPEG.
If I convert it to RGB, the result will be a fully white image.
Is there a way to fix this?
https://www.dropbox.com/s/2d1edk2iu4ixk25/NGC281.png
The input image is a 16-bit grayscale PNG, and it appears PIL has a problem with this. Manually converting it to an 8-bit image before further processing makes it work again.
The problem may originate inside PIL itself. The PyPNG homepage asserts
..PIL only has internal representations (PIL mode) for 1-bit and 8-bit channel values. This makes me wonder if PIL can read PNG files with bit depth 2 or 4 (greyscale or palette), and also bit depth 16 (which PNG supports for greyscale and RGB images).
Then again, that page is from 2009. It could be worth tracking down where PIL is maintained from, and report this as a bug (? Or possibly a feature request?).
I used CGImageGetDataProvider and CGDataProviderCopyData and then get a pointer to the data. The first image I tested was a bmp and this method worked great. However, I changed my image to a JPG because I had read something about the Data Provider possibly being relative to the type of image. The length of that data returned indicates that it is 4 when it should be some large number representing the rows and columns of the image.
What I need is I can ask for the Data Provider to be for a bitmap so I can walk through the data uncompressed?
The data you get out of the data provider will be the data that went into creating the image. For instance, if the image was created using CGImageCreateWithJPEGDataProvider, it would be JPEG data. If you want bitmap data, you will need to make a bitmap, perhaps using CGBitmapContextCreate, and draw the image into the bitmap.
JPEGs are smaller in size than PNGs. So, I thought that if I can make a specific region in a JPEG-file transparent, with some code, maybe I can save some bytes.
So does anyone know how to achieve this with for example PHP or JavaScript?
No. You can't do this. JPGs do not support alpha channels and have no capacity to designate certain colors as transparent either (GIF-style).
There's several issues with this, all of them have to do with that JPEG is a lossy compression format. The JPEG format is optimized for natural images and sharp edges will get blurred. If you intend that a specific pixel should have the value #d67fff there's no guarantee that after color conversion, FDCT, quantization, IDCT and color conversion, the pixel still will have that value. There's also a strong possibility that that pixel value will occur in areas that you don't want.
No. JPEG does not support transparency and is not likely to do so any time
soon. http://www.faqs.org/faqs/jpeg-faq/part1/section-12.html
You cannot do that, the client renders the image and doesn't know that you want it to treat that color as transparent (plus various compression methods on jpeg wouldn't work well with transparencies anyway).
I believe you can go with an 8-bit custom-pallet png, should save you a lot of space. Otherwise 24-bit PNG is your only high color option.
You can convert your image to SVG containing a color information as JPEG and an alpha channel as grayscale mask. Here is a tool I wrote to do it https://github.com/igrmk/transpeg