I'm trying to scaling an image with size = 2496 x 3512 into a PDF document. I'm using PDFBox to generate it but the scaled image ends up blurred.
Here are some snippets:
PDF Page size (A4) returned by page.findMediaBox().createDimension(): java.awt.Dimension[width=612,height=792]
Then I calculate the scaled dimension based on the Page size vs. Image size which returns: java.awt.Dimension[width=562,height=792]
I use the code below in order to calculate the scaled dimension:
public static Dimension getScaledDimension(Dimension imgSize, Dimension boundary) {
int original_width = imgSize.width;
int original_height = imgSize.height;
int bound_width = boundary.width;
int bound_height = boundary.height;
int new_width = original_width;
int new_height = original_height;
// first check if we need to scale width
if (original_width > bound_width) {
//scale width to fit
new_width = bound_width;
//scale height to maintain aspect ratio
new_height = (new_width * original_height) / original_width;
}
// then check if we need to scale even with the new height
if (new_height > bound_height) {
//scale height to fit instead
new_height = bound_height;
//scale width to maintain aspect ratio
new_width = (new_height * original_width) / original_height;
}
return new Dimension(new_width, new_height);
}
And to actually perform the image scaling I'm using Image Scalr API:
BufferedImage newImg = Scalr.resize(img, Scalr.Method.ULTRA_QUALITY, Scalr.Mode.FIT_EXACT,
scaledWidth, scaledHeight, Scalr.OP_ANTIALIAS);
My question is what am I doing wrong? A big image shouldn't be blurred when scaled to a smaller size. Is this something related to the PDF page resolution/size?
Thank you,
Gyo
Ok, I found a way to add images without losing the quality.
Actually to make the image not be blurred I let PDFBox to resize the image by giving it the desired size. Like the code below:
PDXObjectImage ximage = new PDJpeg(doc, new FileInputStream(new File("/usr/gyo/my_large_image.jpg")), 1.0f);
PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, false);
Dimension scaledDim = getScaledDimension(new Dimension(ximage.getWidth(), ximage.getHeight()), page.getMediaBox().createDimension());
contentStream.drawXObject(ximage, 1, 1, scaledDim.width, scaledDim.height);
contentStream.close();
Thank you,
Gyo
Related
I'm working with Java to store and modify .jpg images, (not Android or Swing). I want to transform an image with a new dimension keeping the aspect ratio and filling the background with white color if the new dimension is not proportional to the original image.
BufferedImage image = /*Here i read from disk and load the image */;
image = resizeImage(image, newWidth, newHeight);
ImageIO.write(image, extension, new File(filename + "_" + page + "." + extension));
The function I'm trying to implement is resizeImage: in the example resizes the image but it doesn't keep the aspect ratio.
private static BufferedImage resizeImage(BufferedImage originalImage, int width, int height) {
BufferedImage resizedImage = new BufferedImage(width, height, originalImage.getType());
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
I think a picture will be more illustrative of what I'm asking for:
If the original image is 200x200 and is asked to resize to 400x300 the result should be a picture with white margin and the original picture resized inside. In this example should be 300x300.
The problem is not how to resize, it's how to fill the remaining image with white and the original resized image on the center of it.
This code worked for me:
private static BufferedImage resizeImage(BufferedImage originalImage, int newWidth, int newHeight) {
BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, originalImage.getType());
Graphics2D graphics = resizedImage.createGraphics();
graphics.setColor(Color.WHITE);
// fill the entire picture with white
graphics.fillRect(0, 0, newWidth, newHeight);
int maxWidth = 0;
int maxHeight = 0;
// go along the width and height in increments of 1 until one value is equal to the specified resize value
while (maxWidth <= newWidth && maxHeight <= newHeight)
{
++maxWidth;
++maxHeight;
}
// calculate the x value with which the original image is centred
int centerX = (resizedImage.getWidth() - maxWidth) / 2;
// calculate the y value with which the original image is centred
int centerY = (resizedImage.getHeight() - maxHeight) / 2;
// draw the original image
graphics.drawImage(originalImage, centerX, centerY, maxWidth, maxHeight, null);
graphics.dispose();
return resizedImage;
}
Before:
After:
Using PDFBox i am try to set signature to center on the box of rectacle, assume the rectacle size is 120x60 and can be customized and image signature can vary, examples 1000*1000 or 640x320 etc. I am try with resize the signature like the box :
// save and restore graphics if the image is too large and needs to be scaled
cs.saveGraphicsState();
cs.transform(Matrix.getScaleInstance(0.85f, 0.85f));
PDImageXObject img = PDImageXObject.createFromFileByExtension(imageFile, doc);
float wpercent = (rect.getWidth() / img.getWidth());
float newHeight = img.getHeight() * wpercent;
cs.drawImage(img, 0,0, rect.getWidth(), newHeight); //Resize image signature fit to rectangle and resize the height by percent to avoid stretch image
cs.restoreGraphicsState();
try to calculate coordinate inside the box
cs.drawImage(img, rect.getWidth()*0.10,rect.getHeight()*0.10, rect.getWidth(), newHeight);
example image got success set on center image size 1880x1000
if the signature just QR size 1000x1000
the QR got cut off
how to fix that ?
Solved refers to Auto resized image
by adding this function to scale image fit to rectangle
public static Dimension getScaledDimension(Dimension imgSize, Dimension boundary) {
int original_width = imgSize.width;
int original_height = imgSize.height;
int bound_width = boundary.width;
int bound_height = boundary.height;
int new_width = original_width;
int new_height = original_height;
// first check if we need to scale width
if (original_width > bound_width) {
//scale width to fit
new_width = bound_width;
//scale height to maintain aspect ratio
new_height = (new_width * original_height) / original_width;
}
// then check if we need to scale even with the new height
if (new_height > bound_height) {
//scale height to fit instead
new_height = bound_height;
//scale width to maintain aspect ratio
new_width = (new_height * original_width) / original_height;
}
return new Dimension(new_width, new_height);
}
then add to this function
Dimension scaledDim = getScaledDimension(new Dimension(img.getWidth(), img.getHeight()), new Dimension((int)rect.getWidth(), (int)rect.getHeight()));
int x = ((int) rect.getWidth() - scaledDim.width) / 2;
int y = ((int) rect.getHeight() - scaledDim.height) / 2;
cs.drawImage(img, x, y, scaledDim.width, scaledDim.height);
I built a simple app that you can pick a photo of yourself, select a border for it and then save it as image. The way I did this is adding 2 ImageViews on top of each other in a parent view. Then converting this parent view to image and save. However with this way, the resulting image size depends on the device screen size. If the device screen is small, a small final image is generated.
What I want is creating an image file with a size of 500x800 pixels at all times regardless of device. What is the correct way to do this?
The preview on the screen could be small, but when I click save button I need it to be exactly 500x800.
First, convert your image to bitmap by :
Bitmap bitmapImage= BitmapFactory.decodeResource(getResources(), R.drawable.large_icon);
Or, if you have Uri of image then use this to convert it to bitmap:
Bitmap bitmap = BitmapFactory.decodeFile(imageUri.getPath());
Both of this will give you a bitmap of your image.
Now to resize your image use this code:
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, imageWidth, imageHeight, true);
Then convert it into File.
To Add to Jason Answer, we found the best way to scale the image, is to use this to scale it up or down.
public Bitmap scaleCenterCrop(Bitmap source, int newHeight, int newWidth) {
int sourceWidth = source.getWidth();
int sourceHeight = source.getHeight();
// Compute the scaling factors to fit the new height and width, respectively.
// To cover the final image, the final scaling will be the bigger
// of these two.
float xScale = (float) newWidth / sourceWidth;
float yScale = (float) newHeight / sourceHeight;
float scale = Math.max(xScale, yScale);
// Now get the size of the source bitmap when scaled
float scaledWidth = scale * sourceWidth;
float scaledHeight = scale * sourceHeight;
// Let's find out the upper left coordinates if the scaled bitmap
// should be centered in the new size give by the parameters
float left = (newWidth - scaledWidth) / 2;
float top = (newHeight - scaledHeight) / 2;
// The target rectangle for the new, scaled version of the source bitmap will now
// be
RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);
// Finally, we create a new bitmap of the specified size and draw our new,
// scaled bitmap onto it.
Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
Canvas canvas = new Canvas(dest);
canvas.drawBitmap(source, null, targetRect, null);
return dest;
}
Please try to below code to save bitmap image as custom height & width, Below is a snippet of code that will allow you to resize a Bitmap.
public Bitmap getResizeBitmap(Bitmap bmp, int newHeight, int newWidth) {
int width = bmp.getWidth();
int height = bmp.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// CREATE A MATRIX FOR THE MANIPULATION
Matrix matrix = new Matrix();
// RESIZE THE BIT MAP
matrix.postScale(scaleWidth, scaleHeight);
// RECREATE THE NEW BITMAP
Bitmap resizeBitmap = Bitmap.createBitmap(bmp, 0, 0, width, height, matrix, false);
return resizeBitmap;
}
I'm preparing somecompass activity.
I have my rose of winds .png and I want to scale it on activity start and rotate after orientation changed.
The problem is that when i scale my image (onCreate only), after first (and only first) use of rotate method my view is resized one more time, and I have no idea why.
Let me post you my rotate and scale methods. rose is my ImageView instance (ImageView rose)
Please take a look and post any advices. Should I try different way to scale my ImageView ?
Thx for any help !
Rotate (looks like working fine)
public void rotateRose(float angle){
angle = 360 - angle;
Matrix matrix=new Matrix();
rose.setScaleType(ScaleType.MATRIX);
pivX = rose.getDrawable().getBounds().width()/2;
pivY = rose.getDrawable().getBounds().height()/2;
matrix.preRotate((float) angle, pivX, pivY);
rose.setImageMatrix(matrix);
}
Scale (found source link)
private void scaleImage(ImageView view, int boundBoxInDp)
{
// Get the ImageView and its bitmap
Drawable drawing = view.getDrawable();
Bitmap bitmap = ((BitmapDrawable)drawing).getBitmap();
// Get current dimensions
int width = bitmap.getWidth();
int height = bitmap.getHeight();
// Determine how much to scale: the dimension requiring less scaling is
// closer to the its side. This way the image always stays inside your
// bounding box AND either x/y axis touches it.
float xScale = ((float) boundBoxInDp) / width;
float yScale = ((float) boundBoxInDp) / height;
float scale = (xScale <= yScale) ? xScale : yScale;
// Create a matrix for the scaling and add the scaling data
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
// Create a new bitmap and convert it to a format understood by the ImageView
Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
BitmapDrawable result = new BitmapDrawable(scaledBitmap);
width = scaledBitmap.getWidth();
height = scaledBitmap.getHeight();
// Apply the scaled bitmap
view.setImageDrawable(result);
// Now change ImageView's dimensions to match the scaled image
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view.getLayoutParams();
params.width = width;
params.height = height;
view.setLayoutParams(params);
//pivX = width/2;
// pivY = height/2;
}
Ok i've got it !
replace
view.setImageDrawable(result);
in Scale method with
view.setImageBitmap(scaledBitmap);
If you are looking for scaling and rotating methods for image view: These above works fine (with this little change )
I need to resize the original buffered image to width 100 px with preserved width/height ratio. Below is the code am using. Could someone help me with this ?
Thanks in advance.
int width = 100;
int height = 100;
BufferedImage resizedImage = new BufferedImage(width, height, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, width, height, null);
g.dispose();
You might want to take a look at imgscalr, it is a simple single class that does exactly this with a simple set of static methods to use: http://www.thebuzzmedia.com/software/imgscalr-java-image-scaling-library/
An example usage would look like:
BufferedImage img = Scalr.resize(src, 100);
There are a number of advanced features around quality, speed and simple image ops available to you as well if you need them and the library has been deployed in production in numerous projects and web applications.
int imageWidth = originalImage.getWidth();
int imageHeight = originalImage.getHeight();
height = imageHeight * width / imageWidth;
// Integer arithmetic doing lossless division last.
However height might now be less or more than 100.
well, can you try
int width = 100;
int height = 100;
height = originalImage.height() / (originalImage.width()/width)