Trying to Convert Image from JPEG to TIFF. The new TIFF size is bigger than JPEG file - python-imaging-library

I have around 5000 images. Some of them are JPEG files. I am trying to use Python Pillow to convert some JPEG files to TIFF. The converted TIFF files are 10 times bigger than the original JPEG files in size. I am not sure what I am doing wrong. If someone can assist me with the problem, I will really appreciate it. Below is my code.
from PIL import Image

import magic
import shutil

import os



class Dev:
#staticmethod
def run():
print(magic.from_file('D:\\APPS\\dipPD\\img-wrk.TIF', mime=True))

 im = Image.open('D:\\APPS\\dipPD\\img-wrk.TIF')

 print("Image Format : ", im.format)
# '''

 print("Image Size : ", os.stat('D:\\APPS\\dipPD\\img-org.TIF').st_size)

 # '''
im.save('D:\\APPS\\dipPD\\img-wrk.TIF', 'TIFF', quality=20, optimize=True
)

 # '''

 print("New Image Size : ", os.stat('D:\\APPS\\dipPD\\img-wrk.TIF').st_size)



if __name__ == '__main__':

 Dev.run()
I have tried different parameters for Image.save() function, but that did not help.

Related

Pillow Image.convert multiframe tiff mode 1 to 'RGB' - not saving all frames

I have a multiframe tiff image with mode 1 that I want to convert to a multiframe tiff with mode 'RGB'. It is only saving a single frame in the output. Am I missing something?
def q(file_path='test.tiff'):
with Image.open(file_path) as image:
if image.mode != 'RGB':
n = image.convert('RGB')
n.save(fp='new.tiff', format="TIFF", save_all=True, compression="None")
return
You need to iterate over the sequence of frames. See here.
Code attributable to above link:
from PIL import Image
with Image.open("animation.gif") as im:
im.seek(1) # skip to the second frame
try:
while 1:
im.seek(im.tell() + 1)
# do something to im
except EOFError:
pass # end of sequence

Determining the size of a PNG from raw bytes

I'm trying to load a sequence of PNG images concatenated together as bytes; I know the number of images, but not their individual file sizes.
Loading the first image is easy with something like
import io
from PIL import Image
buffer = io.BytesIO(image_bytearray)
image = Image.open(buffer)
image.load()
However, I'm not sure how to handle the subsequent images. Two approaches that seem to work but might be too brittle:
Split the bytes based on the PNG header e.g. image_bytearray.split(b"\x89PNG\r\n\x1a\n"). This seems to work, but I'm worried in some edge cases this could appear in a non-header location.
Use BytesIO.tell() to determine how much of the stream was read. This appears to be 4 bytes less than the actual file size; I can add 4 to account for this, but I'm not this won't change in a later version.
Here's a simple example that illustrates the two approaches:
import io
import sys
from PIL import Image
import PIL
def setup_bytes():
"""
Concatenate the bytes of some images. The actual images don't matter
"""
files = ["Tests/images/hopper.png", "Tests/images/test-card.png"]
bytes_out = bytes()
for file in files:
im = Image.open(file)
buffer = io.BytesIO()
im.save(buffer, format="PNG")
print(f"writing {len(buffer.getvalue())} bytes")
bytes_out += buffer.getvalue()
return bytes_out
def read_split(bytes_in):
png_header = b"\x89PNG\r\n\x1a\n"
images_out = []
image_byte_splits = bytes_in.split(png_header)
for image_bytes in image_byte_splits:
if len(image_bytes) == 0:
continue
# add back the header
image = Image.open(io.BytesIO(png_header + image_bytes))
image.load()
print(f"read {len(png_header) + len(image_bytes)} bytes")
images_out.append(image)
return images_out
def read_streaming(bytes_in):
images_out = []
bytes_read = 0
# Read the images back from the bytes (without knowing the sizes).
while bytes_read < len(bytes_in):
buffer = io.BytesIO(bytes_in[bytes_read:])
image = Image.open(buffer)
image.load()
images_out.append(image)
# Start the next read at the end of the current image.
# These extra 4 bytes appear necessary.
read = buffer.tell() + 4
print(f"read {read} bytes?")
bytes_read += read
return images_out
def main():
print(f"python sys.version = {sys.version}")
print(f"Pillow version = {PIL.__version__}")
b = setup_bytes()
read_split(b)
read_streaming(b)
main()
My questions are:
Is splitting safe? Is there a chance that the header could also appear in the body of an image?
Is adding an offset to tell() safe? Is there a way to get the image loading to leave the position at the actual end of the file?
Is there a better way to do this in general? Some of the classes in PngImagePlugin.py look like they'd be useful to examine the chunks without actually decompressing.

loading images into an array python

i am trying to read my own images which are 28 x 28 dimension: the images are stored in a folder called, my_own_images. and the image name is 2828_my_own_3.png, 2828_my_own_7.png etc...
i am using the imagio.imread(image_file_name, as_gray = True). However i get an error for the as_gray. I am trying to convert them into grey scale
****THE CODE IS BELOW****
*import imageio
import glob
import numpy
import matplotlib.pyplot as plt
%matplotlib inline
my_dataset = []
for image_file_name in glob.glob('my_own_images/2828_my_own_?.png'):
print ("loading ... ", image_file_name)
# use the filename to set the correct label
label = int(image_file_name[-5:-4])
# load image data from png files into an array
img_array = imageio.imread(image_file_name)
print(img_array.shape)
# reshape from 28x28 to list of 784 values, invert values
img_data = 255.0 - img_array.reshape(784)
# then scale data to range from 0.01 to 1.0
img_data = (img_data / 255.0 * 0.99) + 0.01
print(numpy.min(img_data))
print(numpy.max(img_data))
# append label and image data to test data set
record = numpy.append(label,img_data)
print(record)
my_dataset.append(record)
pass*
The ERROR im getting:
open() got an unexpected keyword argument 'as_gray'
It seems we are reading the same book (Make Your Own Neural Network), I have encountered the same error with anaconda (I have imageio 2.2.0 Install), so I updated the imageio to 2.3.0, re-launch jupyter Notebook, re-run the code again it work for me. (hope it help you)

sws_scale screws up last pixel row in smaller x264 mp4 encoding

I am muxing pictures in the PIX_FMT_ARGB format into an mp4 video.
All of it works well, except that the last pixel row of the outgoing image is screwed up, in most cases the last row is completely black, sometimes there are other colors, it seems somehow dependant on the machine it runs on.
I am absolutely sure that the error must be in sws_scale, as I am saving the images before and after the scaling. The input images do not have the error, but after the sws_scale() I save the yuv image and the error is apparent.
Here is an example:
Original
Yuvfile (after sws_scale)
At the bottom of the Yuvfile, you will see the black row.
This is how I do the scaling (it is after the official ffmpeg examples, more or less):
static int sws_flags = SWS_FAST_BILINEAR | SWS_ACCURATE_RND;
if (img_convert_ctx == NULL)
{
img_convert_ctx = sws_getContext( srcWidth, srcHeight,
PIX_FMT_ARGB,
codecContext->width, codecContext->height,
codecContext->pix_fmt,
sws_flags, NULL, NULL, NULL );
if (img_convert_ctx == NULL)
{
av_log(c, AV_LOG_ERROR, "%s","Cannot initialize the conversion context\n");
exit(1);
}
}
fill_image(tmp_picture, pic, pic_size, frame_count, ptr->srcWidth, ptr->srcHeight );
sws_scale(img_convert_ctx, tmp_picture->data, tmp_picture->linesize,
0, srcHeight, picture->data, picture->linesize);
I also tried a number of different SWS_ flags, but all yield the same result.
Could this be a bug in sws_scale or am I doing something wrong? I am using the latest version of the ffmpeg libraries.
The problem was this function:
fill_image(tmp_picture, pic, pic_size, frame_count, ptr->srcWidth, ptr->srcHeight );
It did not copy the input image to the tmp_picture correctly. Indeed skipped the last line.
Morale: Do not trust years-old functions :D
180 is not a multiple of 8, this could be the reason for the black row. Can you try scaling it to the nearest multiple of 8,say 184 or 192(multiple of 16)? Non h264 codecs need multiple of 8 as height.

iPhone SDK: accessing indexed color PNG images

I'm interested in loading indexed-color PNG images in my iPhone application. Once they're loaded, I want to access the images on a per-pixel basis. In particular, I want to get the index of the color (rather than the color itself) of individual pixels.
Unfortunately, there does not seem to be a way to access pixels via the UIImage class, let alone color index of a pixel. I'm also taking a look at Quartz2D-related APIs, but so far things look bleak.
I'd greatly appreciate any suggestions.
I'm hoping I won't have to port the necessary code from libpng.
Thanks in advance!
UPDATE: I'm able to load the PNG using Quartz2D, but for some reason it automatically converts my indexed-color 8bit PNG to a 32-bit ARGB PNG. Any thoughts how I might prevent this?
UPDATE 2: The reason this is important is due to memory limitations. I'm trying to keep the raster from blowing up form eight bits per pixel to thirty two to avoid the overhead. If anyone has the magic answer for me, 100 points are yours!
By loading the image as a CGImage rather than an UIImage, using CGImageCreateWithPNGDataProvider(), you might be able to get an indexed color space. See:
http://developer.apple.com/iphone/library/documentation/GraphicsImaging/Reference/CGColorSpace/Reference/reference.html
which lists CGColorSpaceCreateIndexed(), CGColorSpaceGetColorTable() and more. Use CGColorSpaceGetModel(CGImageGetColorSpace(img)) to see if the color space you end up with is an indexed one, then use CGImageGetDataProvider() to get a CGDataProviderRef, which you can use with CGDataProviderCopyData() to get to the actual bitmap data...
edit a bounty always gets things going. I tested and it just works. (sorry for the crappy handling, this is proof of concept of course)
NSString *path = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:#"test.png"];
printf("path: %s\n",[path UTF8String]);
NSData *file = [[NSFileManager defaultManager] contentsAtPath:path];
if ( !file ) printf("file failed\n");
CGDataProviderRef src = CGDataProviderCreateWithCFData(file);
if ( !src ) printf("image failed\n");
CGImageRef img = CGImageCreateWithPNGDataProvider(src, NULL, NO, kCGRenderingIntentDefault);
if ( !img ) printf("image failed\n");
printf("Color space model: %d, indexed=%d\n",
CGColorSpaceGetModel(CGImageGetColorSpace(img)),
kCGColorSpaceModelIndexed);
output:
path: /Users/..../638...8C12/test.app/test.png
Color space model: 5, indexed=5
qed?
ps. my test image is from libgd, through php, using
$img = imagecreatefrompng("whateverimage.png");
imagetruecolortopalette($img,false,256);
header("Content-Type: image/png");
imagepng($img);
which results in my case (b/w image) in
$ file test.png
test.png: PNG image, 2000 x 300, 1-bit colormap, non-interlaced
edit^2 This is how you access the bitmap data. ASCII art ftw!
CGDataProviderRef data = CGImageGetDataProvider(img);
NSData *nsdata = (NSData *)(CGDataProviderCopyData(data));
char *rawbuf = malloc([nsdata length]);
if ( !rawbuf ) printf("rawbuf failed\n");
[nsdata getBytes:rawbuf];
int w = CGImageGetWidth(img);
int h = CGImageGetHeight(img);
int bpl = CGImageGetBytesPerRow(img);
printf("width: %d (%d bpl), height: %d, pixels: %d, bytes: %d\n",w,bpl,h,bpl*h,[nsdata length]);
if ( [nsdata length] != bpl*h )
{
printf("%d pixels is not %d bytes, i may be crashing now...\n",bpl*h,[nsdata length]);
}
for ( int y=0;y<h; y++ )
{
for ( int x=0;x<w; x++ )
{
char c = rawbuf[y*bpl+x];
while ( !isalnum(c) ) c += 31; //whoa!
printf("%c",c);
}
printf("\n");
}