iTextSharp ultra wide image in multiple pages horizontally - image

I have a problem with iTextSharp. I have an image of 20000x1000 and I have to put it in a PDF with page size A1 horizontal. The tricky thing is that I need to adjust the height of the image to the PDF and print multiple pages wide in relation to the image.
I tried with this but it generates a PDF with a single page and the image adjusted both width and height.
Rectangle pageSize = PageSize.A1;
Document doc = new Document(pageSize.Rotate(), 10f, 10f, 10f, 10f);
PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(#"C:\TestFiles\Default.pdf", FileMode.Create));
doc.Open();
Image image = Image.GetInstance(#"C:\TestFiles\image.png");
PdfPTable table = new PdfPTable(1);
table.WidthPercentage = 100;
PdfPCell c = new PdfPCell(image, true);
c.Border = PdfPCell.NO_BORDER;
c.Padding = 5;
c.Image.ScaleAbsoluteHeight(pageSize.Height);
table.AddCell(c);
doc.Add(table);
doc.Close();
Thank you in advance for your help.

Using a table is not the way to go for your requirement.
First let's take a look at how you can scale the image so that the height is adapted to the height of a rotated A1 document:
Image image = Image.GetInstance(#"C:\TestFiles\image.png");
image.ScaleToFit(image.ScaledWidth, PageSize.A1.Width);
The ScaleToFit() method scales an image so that it fits into a rectangle. In this case, we don't want the width to be reduced, so we define the width of that rectangle as equal to the width of the original image. We do want to scale the height so that it fits the height of a rotated A1 page. As we rotate the A1 page, we have to use PageSize.A1.Width instead of PageSize.A1.Height.
Suppose that you have an image that measures 500 x 1500, then the scaled image will have size 500 by 2000 because that image fits a rectangle of 500 by 1684.
Suppose that you have an image that measures 500 x 2000, then the scaled image will be 421 x 1684. The height will be reduced to fit the rotated A1 page, and the width will be reduced accordingly.
Suppose that you have an image of 5000 by 2000, then the scaled image will be 4210 x 1684.
Now we have to add the same image as many times as needed until the complete image is rendered. Note that the image bytes will only be stored once in the PDF: those bytes are reused for every page.
Float offset = 0;
while (offset <= img.ScaledWidth) {
document.NewPage();
img.SetAbsolutePosition(-offset, 0);
document.Add(img);
offset += PageSize.A1.HEIGHT;
}
What happens in the above code snippet? On the first page, we add the image at position (0, 0) which is means that the lower-left corner of the image will coincide with the lower left corner of the page.
If the image fits the page, e.g. in case the width was scaled smaller than the new offset (2384), no new page will be triggered. If the image doesn't fit the page (e.g. because the scaled width is 4210 which is greater than 2384) a new page will be created, and the same image will be added with a new offset (e.g. (-2384, 0)).
Suppose that the width of the scaled image is indeed 4210 and the width of the page is 2384, then the offset after a second page is added will be 4768. That is greater than 4210, so there will be no third page.

Related

Intervention Image resize different pictures under one

Laravel has Intervention Image, with which you can resize images
// create instance
$img = Image::make('public/foo.jpg');
// resize image to fixed size
$img->resize(300, 200);
Everything is fine if the uploaded image has a size of 3000 x 2000 and we will make 300 x 200 from it.
But if we load images with different heights and widths, and do a 300 x 200 resize, then the images will stretch and look awful.
I need them to be cut a little at the edges.
I have tried using $img->fit(300, 200); but it cuts too much.
Is it possible to do two steps in Intervention Image for resizing, for example, defining the size and removing a few unnecessary parts to make the picture look more or less normal?
To remove a few unnecessary parts you can use the crop() function first and then resize the image maintaining its aspect ration.
$img->crop(width, height, x, y);
This function cuts out a rectangular part of the current image with given width and height. Define optional x,y coordinates to move the top-left corner of the cutout to a certain position. By default the rectangular part will be centered on the current image if you do not provide the x,y co-ordinates.
After cropping the image, you can resize the image maintaining its aspect ration, so the image will not look stretchy or abnormal.
// resize the image to a width of 300 and constrain aspect ratio (auto height)
$img->resize(300, null, function ($constraint) {
$constraint->aspectRatio();
});
// resize the image to a height of 200 and constrain aspect ratio (auto width)
$img->resize(null, 200, function ($constraint) {
$constraint->aspectRatio();
});
However, if you always want the image to be a specific dimension, which is in your case 300 X 200 , You can try the fit function with the callback functionality to retain maximal original image size.
// add callback functionality to retain maximal original image size
$img->fit(300, 200, function ($constraint) {
$constraint->upsize();
});

Display an image scale space in MATLAB

I have 8 images and I want to show them in a scale-space format shown below. The original image height and width is 256. Then on right side of original image, at every level the size is reduced by 2. Like here, image height and width is 256. On the right side of original image, height and width is 128, 64, 32, 16, 8, 4 , 2.
I have all the images in their respective dimensions. I just want to know how do I arrange the images according the pattern shown below. Thanks in advance.
This looks like you are trying to build a scale-space and displaying the results to the user. This isn't a problem to do. Bear in mind that you will have to do this with for loops, as I don't see how you will be able to do this unless you copy and paste several lines of code. Actually, I'm going to use a while loop, and I'll tell you why soon.
In any case, you need to declare an output image that has as many rows as the original image, but the columns will be 1.5 times the original image to accommodate for the images on the right.
First, write code that places the original image on the left side, and the version that is half the size on the right. Once you do this, you write a for loop, use indexing to place the images in the right spots until you run out of scales, and you need to keep track of where the next image starts and next image ends. Bear in mind that the origin of where to write the next images after the first subsampled one will start at the column location of the original image, and the row is right where the previous one ends. As an example, let's use the cameraman.tif image that is exactly 256 x 256, but I will write code so that it fits any image resolution you want. When I subsample the image, I will use imresize in MATLAB to help with the resizing of the image, and I'll specify a sampling factor of 0.5 to denote the subsampling by 2. The reason why I would use a while loop instead, is because we can keep looping and resizing until one of the dimensions of the resized image is 1. When this is the case, there are no more scales to process, and so we can exit.
As such:
%// Read in image and get dimensions
im = imread('cameraman.tif');
[rows,cols] = size(im);
%// Declare output image
out = zeros(rows, round(1.5*cols), 'uint8');
out(:,1:cols) = im; %// Place original image to the left
%// Find first subsampled image, then place in output image
im_resize = imresize(im, 0.5, 'bilinear');
[rows_resize, cols_resize] = size(im_resize);
out(1:rows_resize,cols+1:cols+cols_resize) = im_resize;
%// Keep track of the next row we need to write at
rows_counter = rows_resize + 1;
%// For the rest of the scales...
while (true)
%// Resize the image
im_resize = imresize(im_resize, 0.5, 'bilinear');
%// Get the dimensions
[rows_resize, cols_resize] = size(im_resize);
%// Write to the output
out(rows_counter:rows_counter+rows_resize-1, cols+1:cols+cols_resize) = ...
im_resize;
%// Move row counter over for writing the next image
rows_counter = rows_counter + rows_resize;
%// If either dimension gives us 1, there are no more scales
%// to process, so exit.
if rows_resize == 1 || cols_resize == 1
break;
end
end
%// Show the image
figure;
imshow(out);
This is the image I get:

zoom an image to fit a screen horizontally - algorithm

This is a general question regarding an algorithm to zoom an image to fit the width of a screen, there are some givens and some constraints. We can assume we are using Java but this question is more mathematical that language dependent.
First of all, the image loads and fits into the dimensions of the screen vertically first, not horizontally.
We can get the dimensions of the screen and the dimensions of the image with methods, but we cannot set the dimensions of either (We only have getters not setters).
imageWidth = image.getWidth(); //integer
imageHeight = image.getHeight(); //integer
screenWidth = screen.getWidth(); //integer
screenHeight = screen.getHeight(); //integer
The only method to resize the image is by setting scale (zooming essentially).
image.setScale(some float); // optionally image.setZoom(integer);
What I would like to know is how to calculate the scale (zoom) level for some l x h image so that it fits a L x H screen horizontally?
All you have to do to make the Image fill your screen is scale along the x axis:
scaling_factor = screen.getWidth()/image.getWidth()
image.setScale(zoom_factor);
The formula is very intuitive:
The image height is irrelevant. The scaling you desire would be the same for a landscape and vertical image, as long as the width of both images are the same
When the image's width increases, your scaling factor decreases
When your screen size increses, the scaling factor increases.

Image scaling inside a canvas

Let's assume we have a container with the size of 500 x 300 (w x h).
Inside this container we have a canvas with the same size, but with a different reference system inside it, with the size of 700 x 1000.
When I put an image of 700 x 1000 in this canvas it will obviously appear distorted, because the canvas occupies the entire 500 x 300 pixels of its parent container - even if inside it is still 700 x 1000.
Now, I am trying to figure out a formula to scale the image in the interlal reference system so the image doesn't appear distorted then loaded in the canvas.
Can anybody help?
First of all, if you have w = 700, h = 1000, i.e. w_container / w_canvas = 5/7 != h_container / h_canvas = 3/10, you will not be able to load you image not being distorted and taking entire space of the container. I just can tell you how to resize your image properly.
To save the width-height ratio of your image (equals 7/10, I think this is what you mean under "distorted image") you should calculate how your image's ratio rescales after putting the image on the canvas.
canvas_ratio(7/10) * x = container_ratio(5/3), hence x = 50/21. So if your image has the ratio y, then it will become y*x = y*50/21.
So you should just resize your image before putting it on the canvas such a way that after multiplying this ratio by x it would be 7/10 (the ratio when your image looks perfect). We have an equation y*50/21 = 7/10, hence y = 147/500. That's the ratio your image should have!
For example, you can make image size 294x1000, and after putting it to the canvas it will have height of 300 pixels in your container's coordinate system and 294*(500/700) = 210 pixel width (unfortunately, not 500). Hope this will be useful information for you.
Good luck!

Resize an image to specific ratio without enlarging it

I need to generate new dimensions for an image to match a ratio of a given width and height ...but without increasing the size of the original.
The concept seems oh so simple yet I can't seem to join the dots.
Also, for code samples the language is PHP.
Update:
This is what I have so far:
http://codepad.org/fTdCNhQf
This is the output I need:
Example Image • (can't embed yet)
Since enlarging is not an option, your only options are cropping and extending.
Try this: let's say your image is W*H, and the desired aspect ratio of width to height is R.
Using the width and the aspect ratio, calculate the target height TH = W/R
Using the height and the aspect ratio, calculate the target width TW = H*R
Calculate area changes aH = ABS(TH-H)*W and aW = ABS(TW-W)*H
if aH is less than aW, use target width; pad or crop the image horizontally based on the sign of TH-H
Otherwise, use target height; pad or crop the image vertically based on the sigh of TW-W
Here is a quick example:
Target R: 5/6
Image: W=200, H= 300;
TH = 200/5*6 = 240
TW = 300*5/6 = 250
aH = 60*200=12000
aW = 50*300=15000
Resulting action: since aH is less than aW, crop image vertically to 240
Are you using something like ImageMagick libraries to generate an image or do you just need to generate the new dimensions based on a known ratio? Also, do you need to discover the ratio from the existing image?
This may be useful then:
http://www.zedwood.com/article/119/php-resize-an-image-with-gd

Resources