Low quality when converting PDF to JPG - ruby

I'm attempting to use Imagemagic(RMAgick) to convert PDF-document into image. Original PDF is created from an image too(not native vector PDF).
image = Magick::Image::from_blob(original_pdf) { self.format = 'PDF' }
image[0].format = 'JPG'
image[0].to_blob
image[0].write(to_file.jpg) {
self.quality = 100
self.density = 144
}
But resulting image has too low quality, when printing. Original PDF has good quality in same time.
I'm trying to use these options
self.quality = 100
self.density = 144
or using PNG rather JPG, but all this doesn't work, only increase image size in kb ).

Assuming original_pdf is content of pdf file, e.g.:
original_pdf = File.open('from_file.pdf', 'rb').read
Then apply quality options in block of method from_blob
instead of block of method write:
image = Magick::Image::from_blob(original_pdf) do
self.format = 'PDF'
self.quality = 100
self.density = 144
end
image[0].format = 'JPG'
image[0].to_blob
image[0].write('to_file.jpg')
Look also quality options for Magick::ImageList.new method.

Related

Google CloudML serving_input_receiver_fn() b64 decode error

I am sending a base64 encoded image via AJAX POST to a model stored in Google CloudML. I am getting an error telling me that my input_fn(): is failing to decode the image and transform it into jpeg.
Error:
Prediction failed: Error during model execution:
AbortionError(code=StatusCode.INVALID_ARGUMENT,
details="Expected image (JPEG, PNG, or GIF), got
unknown format starting with 'u\253Z\212f\240{\370
\351z\006\332\261\356\270\377' [[{{node map/while
/DecodeJpeg}} = DecodeJpeg[_output_shapes=
[[?,?,3]], acceptable_fraction=1, channels=3,
dct_method="", fancy_upscaling=true, ratio=1,
try_recover_truncated=false,
_device="/job:localhost/replica:0 /task:0
/device:CPU:0"](map/while/TensorArrayReadV3)]]")
Below is the full Serving_input_receiver_fn():
The first step I believe is to handle the incoming b64 encoded string and decode it. This is done with:
image = tensorflow.io.decode_base64(image_str_tensor)
The next step I believe is to open the bytes, but this is where I dont know how to handle the decoded b64 string with tensorflow code and need help.
With a python Flask app this can be done with:
image = Image.open(io.BytesIO(decoded))
pass the bytes through to get decoded by tf.image.decode_jpeg ????
image = tensorflow.image.decode_jpeg(image_str_tensor, channels=CHANNELS)
Full input_fn(): code
def serving_input_receiver_fn():
def prepare_image(image_str_tensor):
image = tensorflow.io.decode_base64(image_str_tensor)
image = tensorflow.image.decode_jpeg(image_str_tensor, channels=CHANNELS)
image = tensorflow.expand_dims(image, 0) image = tensorflow.image.resize_bilinear(image, [HEIGHT, WIDTH], align_corners=False)
image = tensorflow.squeeze(image, axis=[0])
image = tensorflow.cast(image, dtype=tensorflow.uint8)
return image
How do I decode my b64 string back into jpeg and then convert the jpeg to a tensor?
This is a sample for processing b64 images.
HEIGHT = 224
WIDTH = 224
CHANNELS = 3
IMAGE_SHAPE = (HEIGHT, WIDTH)
version = 'v1'
def serving_input_receiver_fn():
def prepare_image(image_str_tensor):
image = tf.image.decode_jpeg(image_str_tensor, channels=CHANNELS)
return image_preprocessing(image)
input_ph = tf.placeholder(tf.string, shape=[None])
images_tensor = tf.map_fn(
prepare_image, input_ph, back_prop=False, dtype=tf.uint8)
images_tensor = tf.image.convert_image_dtype(images_tensor, dtype=tf.float32)
return tf.estimator.export.ServingInputReceiver(
{'input': images_tensor},
{'image_bytes': input_ph})
export_path = os.path.join('/tmp/models/json_b64', version)
if os.path.exists(export_path): # clean up old exports with this version
shutil.rmtree(export_path)
estimator.export_savedmodel(
export_path,
serving_input_receiver_fn=serving_input_receiver_fn)

Using MATLAB to save a montage of many images as one large image file at full resolution

I am trying to save a montage of many (~500, 2MB each) images using MATLAB function imwrite, however I keep getting this error:
Error using imwrite>validateSizes (line 632)
Images must contain fewer than 2^32 - 1 bytes of data.
Error in imwrite (line 463)
validateSizes(data);
here is the code I am working with:
close all
clear all
clc
tic
file = 'ImageRegistrations.txt';
info = importdata(file);
ImageNames = info.textdata(:,1);
xoffset = info.data(:,1);
yoffset = info.data(:,2);
for i = 1:length(ImageNames);
ImageNames{i,1} = imread(ImageNames{i,1});
ImageNames{i,1} = flipud(ImageNames{i,1});
end
ImageNames = flipud(ImageNames);
for i=1:length(ImageNames)
diffx(i) = xoffset(length(ImageNames),1) - xoffset(i,1);
end
diffx = (diffx)';
diffx = flipud(diffx);
for j=1:length(ImageNames)
diffy(j) = yoffset(length(ImageNames),1) - yoffset(j,1);
end
diffy = (diffy)';
diffy = flipud(diffy);
matrix = zeros(max(diffy)+abs(min(diffy))+(2*1004),max(diffx)+abs(min(diffx))+(2*1002));
%matrix(1:size(ImageNames{1,1},1),1:size(ImageNames{1,1},2)) = ImageNames{1,1};
for q=1:length(ImageNames)
matrix((diffy(q)+abs(min(diffy))+1):(diffy(q)+abs(min(diffy))+size(ImageNames{q,1},1)),(diffx(q)+abs(min(diffx))+1):((diffx(q)+abs(min(diffx))+size(ImageNames{q,1},2)))) = ImageNames{q,1};
end
graymatrix = mat2gray(matrix);
graymatrix = flipud(graymatrix);
figure(2)
imshow(graymatrix)
imwrite(graymatrix, 'montage.tif')
toc
I use imwrite because it perserves the final montage in a full resolution file, whereas if I simply click save on the figure file it saves it as a low resolution file.
thanks!
Error does what it says on the tin, really. There is some sort of inbuilt limitation to input variable size in imwrite, and you're going over it.
Note that most images are stored as uint8 but I would guess that you end up with doubles as a result of your processing. That increases the memory usage.
It may be, therefore, that casting to another type would help. Try using im2uint8 (presuming your variable graymatrix is double, scaled between 0 and 1), before calling imwrite.

Writing a multipage tif to file in matlab

I'm trying to write a a multipage (1024 pages to be exact) to file.
for frame=1:num_images
imwrite(output(:,:,frame), 'output.tif', 'tif', 'WriteMode', 'append', 'compression', 'none');
end
I tried this, but writing Int32 to tiff is not supported by imwrite.
I've also tried
tiffObj = Tiff('output.tif', 'w');
tiffObj.setTag('ImageLength', x_size);
tiffObj.setTag('ImageWidth', y_size);
tiffObj.setTag('Photometric', Tiff.Photometric.MinIsBlack);
tiffObj.setTag('BitsPerSample', 32);
tiffObj.setTag('SamplesPerPixel', 1);
tiffObj.setTag('RowsPerStrip', 64);
tiffObj.setTag('SampleFormat', Tiff.SampleFormat.Int);
tiffObj.setTag('TileWidth', 128);
tiffObj.setTag('TileLength', 128);
tiffObj.setTag('Compression', Tiff.Compression.None);
tiffObj.setTag('PlanarConfiguration',Tiff.PlanarConfiguration.Chunky);
tiffObj.setTag('Software', 'MATLAB');
tiffObj.write(output);
tiffObj.close();
The tif I imread() has 1 SamplesPerPixel per frame, but when I try to use the same value I get
SamplesPerPixel is 1, but the number of image planes provided was 1204.
If I set it to 1204 Imagej complains
Unsupported SamplesPerPixel: 1204
This is rather frustrating.
The correct way to write multiple pages to a TIFF file is to call Tiff.writeDirectory after each page (2D image) has been written. I agree, the MATLAB documentation is not very clear there, knowing LibTIFF helps in using the Tiff class. For example:
image = zeros([140,160,16],'uint8'); % this is the image we'll write, should have some actual data in it...
t = Tiff('testing.tif','w');
tagstruct.ImageLength = size(image,1);
tagstruct.ImageWidth = size(image,2);
tagstruct.SampleFormat = 1; % uint
tagstruct.Photometric = Tiff.Photometric.MinIsBlack;
tagstruct.BitsPerSample = 8;
tagstruct.SamplesPerPixel = 1;
tagstruct.Compression = Tiff.Compression.Deflate;
tagstruct.PlanarConfiguration = Tiff.PlanarConfiguration.Chunky;
for ii=1:size(image,3)
setTag(t,tagstruct);
write(t,image(:,:,ii));
writeDirectory(t);
end
close(t)

TYPO3: Images are rendered with unwanted Outline/Border

In one case i am rendering all images from all news entries from one specific category inside an unordered list. Each image is wrapped inside an anchor element which itself is wrapped inside a list-item. Each image is 100% white and shall be displayed transparent.
After solving a few transparency related issues i now stand before the problem that ALL images are given an outline which i am not aiming for - since in some cases it might clash with the background (the background Image is changing sometimes). Either i have something missing in my code or something is wrong with the images i am trying to use.
Here is the typoscript code used for rendering the images:
myMarker.20 < plugin.tt_news
myMarker.20
{
code >
code = LIST
templateFile = fileadmin/templates/ext/tt_news/myMarker_template.html
excludeAlreadyDisplayedNews = 0
limit = 6
categoryMode = 1
categorySelection = 5
catImageMode = 0
catTextMode = 1
listOrderBy = title asc
displayList
{
image >
image.stdWrap.cObject = IMAGE
image.stdWrap.cObject.linkWrap = |
image.stdWrap.cObject.linkWrap.insertData = 1
image.stdWrap.cObject.titleText.field = title
image.stdWrap.cObject.file = field:image
image.stdWrap.cObject.file = GIFBUILDER
image.stdWrap.cObject.file
{
format = png
XY = 130, 48
transparentBackground = 1
backColor = transparent
10 = IMAGE
10
{
offset = 0, 48-[10.h]/2
border = 0
file
{
import = uploads/pics/
import.data = field:image
import.listNum = 0
import.override.field = image
maxW = 130
maxH = 48
quality = 100
}
}
}
}
} # myMarker
Maybe someone has an idea? Thanks for reading/help in advance anyway :)
Solved by not using gifbuilder.

rmagick compress and convert png to jpg

I am trying to compress a png and save it as jpg:
i = Image.read("http://ds4jk3cl4iz0o.cloudfront.net/e2558b0d34221d3270189320173dabc2.png").first
it's size is 799 kb:
http://ds4jk3cl4iz0o.cloudfront.net/e2558b0d34221d3270189320173dabc2.png=>e2558b0d34221d3270189320173dabc2.png PNG 640x639 640x639+0+0 DirectClass 8-bit 799kb
I set the format to jpeg and quality to 10 (i.e very poor quality so file size should be greatly reduced):
i.format = 'JPEG'
i.write("itest10.png") { self.quality = 10 }
The size actually increases to 800kb!
=> http://ds4jk3cl4iz0o.cloudfront.net/e2558b0d34221d3270189320173dabc2.png=>itest40.png PNG 640x639 640x639+0+0 DirectClass 8-bit 800kb
1) Why?
2) How can I compress the photo so the size is < 150kb ?
Thanks!
The use of '.png' extension will change the format back to PNG on the call to write.
There are two possible solutions.
First, I'd recommend using the normal file extension for your format if possible, because a lot of computer systems will rely on that:
i = Image.read( 'demo.png' ).first
i.format = 'JPEG'
i.write( 'demo_compressed.jpg' ) { |image| image.quality = 10 }
If this is not possible, you can set the format inside the block passed to write, and this will apply the format after the extension has been processed:
i = Image.read( 'demo.png' ).first
i.write( 'demo_compressed.png' ) do |image|
image.format = 'JPEG'
image.quality = 10
end
In both the above cases, I get the expected high compression (and low quality) jpeg format image.
This has been updated due to recent RMagick changes (thanks to titan for posting comment). The orginal code snippets were
i.write( 'demo_compressed.jpg' ) { self.quality = 10 }
and
i.write( 'demo_compressed.png' ) do
self.format = 'JPEG'
self.quality = 10
end
These may still work in older RMagick installations.
I tried the other answer and I was still having issues with the transparency. This code here work fine for me:
img_list = Magick::ImageList.new
img_list.read( 'image.png' )
img_list.new_image( img_list.first.columns, img_list.first.rows ) {
self.background_color = "white"
}
imageJPG = img_list.reverse.flatten_images
imageJPG.write( "out.jpg" )
The idea is first create an imageList then load the PNG image into it and after that add a new image to that list and set its bg to be white. Then just reverse the order of the list then flatten the image list into a single image. To add compression just do the self.quality thing from the above answer.

Resources