How to rotate around the image center by itext? - java

double degPi = degrees * Math.PI / 180;
double a = Math.cos(degPi)*tImgCover.getScaledHeight();
double b = Math.sin(degPi)*tImgCover.getScaledWidth();
double c = -Math.sin(degPi) * tImgCover.getScaledHeight();
double d = Math.cos(degPi)* tImgCover.getScaledWidth();
double e = absX;
double f = absY;
contentByte.addImage(imgae, a, b, c, d, e, f);/*add image*/
How to rotate around the image center by itext?

If we have an Image image and coordinates x, y, we can draw the image without rotation with its lower left corner at the given coordinates like this
contentByte.addImage(image, image.getWidth(), 0, 0, image.getHeight(), x, y);
A bitmap image from the resources has a size of 1x1 with the coordinate origin at its lower left. Thus, this operation stretches the image to its correct size and moves it so its lower left is at the given coordinates.
If we want to draw the same image as if the one drawn above was rotated around its center by an angle rotate, therefore, we can do this by moving the 1x1 image so that the origin is in its center, stretch it to its correct size, rotate it, and then move the origin (which still is at the center of the rotated image) to the center of the unrotated image. These operations are easier to express using AffineTransform instances (from package com.itextpdf.awt.geom) instead number tupels. Thus:
// Draw image as if the previous image was rotated around its center
// Image starts out being 1x1 with origin in lower left
// Move origin to center of image
AffineTransform A = AffineTransform.getTranslateInstance(-0.5, -0.5);
// Stretch it to its dimensions
AffineTransform B = AffineTransform.getScaleInstance(image.getWidth(), image.getHeight());
// Rotate it
AffineTransform C = AffineTransform.getRotateInstance(rotate);
// Move it to have the same center as above
AffineTransform D = AffineTransform.getTranslateInstance(x + image.getWidth()/2, y + image.getHeight()/2);
// Concatenate
AffineTransform M = (AffineTransform) A.clone();
M.preConcatenate(B);
M.preConcatenate(C);
M.preConcatenate(D);
//Draw
contentByte.addImage(image, M);
(AddRotatedImage.java test method testAddRotatedImage)
For example drawing both images using
int x = 200;
int y = 300;
float rotate = (float) Math.PI / 3;
results in something like this:
With a Flip
The OP asked in a comment
how to add rotate and flip image?
For this you simply insert a mirroring affine transformation into the sequence of transformations above.
Unfortunately the OP did not mention which he meant a horizontal or a vertical flip. But as changing the rotation angle accordingly transforms one in the other, that isn't really necessary, either.
// Draw image as if the previous image was flipped and rotated around its center
// Image starts out being 1x1 with origin in lower left
// Move origin to center of image
AffineTransform A = AffineTransform.getTranslateInstance(-0.5, -0.5);
// Flip it horizontally
AffineTransform B = new AffineTransform(-1, 0, 0, 1, 0, 0);
// Stretch it to its dimensions
AffineTransform C = AffineTransform.getScaleInstance(image.getWidth(), image.getHeight());
// Rotate it
AffineTransform D = AffineTransform.getRotateInstance(rotate);
// Move it to have the same center as above
AffineTransform E = AffineTransform.getTranslateInstance(x + image.getWidth()/2, y + image.getHeight()/2);
// Concatenate
AffineTransform M = (AffineTransform) A.clone();
M.preConcatenate(B);
M.preConcatenate(C);
M.preConcatenate(D);
M.preConcatenate(E);
//Draw
contentByte.addImage(image, M);
(AddRotatedImage.java test method testAddRotatedFlippedImage)
The result with the same image as above:
With Interpolation
The OP asked in a yet another comment
How anti aliasing ?
The iText Image class knows an Interpolation property. By setting it to true (before adding the image to the document, obviously),
image.setInterpolation(true);
low resolution images are subject to interpolation when drawn.
E.g. using a 2x2 image with differently colored pixels instead of the image of Willi, you get the following results, first without interpolation, then with interpolation:
Confer the AddRotatedImage.java test testAddRotatedInterpolatedImage which adds this image:
Beware: iText Image property Interpolation effectively sets the Interpolate entry in the PDF image dictionary. The PDF specification notes in this context:
NOTE A conforming Reader may choose to not implement this feature of PDF, or may use any specific implementation of interpolation that it wishes.
Thus, on some viewers interpolation may occur differently than in your viewer, maybe even not at all. If you need a specific kind of interpolation on every viewer, upscale the image with the desired amount of interpolation / anti-aliasing before loading it into an iText Image.

public static BufferedImage rotateClockwise90( BufferedImage inputImage ){
int width = inputImage.getWidth();
int height = inputImage.getHeight();
BufferedImage returnImage = new BufferedImage( height, width , inputImage.getType() );
for( int x = 0; x < width; x++ ) {
for( int y = 0; y < height; y++ ) {
returnImage.setRGB( height-y-1, x, inputImage.getRGB( x, y ) );
}
}
return returnImage;
}

Related

Java how to rotate an image by 90 degrees?

public void rotateImage90(){
this.redisplayImage();
for (int x = 0; x < this.image.length; x++)
for (int y = 0; y < this.image[0].length; y++){
this.image[x][y] = this.image[this.image.length-1-x][y];
}
}
I dont know what to do from here to rotate an image 90 degrees. Please help if u can
Here is one way to do it. There may be better ways using an AffineTransForm. This method does not explicitly rotate the source image but rotates the target graphics context, and then writes the image to that.
read in the source image. In this case into buf.
extract the dimensions.
create the target rotated BufferedImage (output) reversing the source dimensions and copying the image type (JPEG, PNG, etc).
Now get the graphics context for the output image.
Since you want to rotate about the center, translate to the target center anchors and then rotate in radians to 90 degrees (Math.PI/2).
Now get ready to write the source image (buf) into the rotated context of (output). However, the anchors need to be retranslated to the starting position for the source file (buf). So translate back but reverse the width and height anchors to match the width and height of the source file.
then draw the original image (buf) into the context rotated buffered image (output).
And write the rotated image (output) to the file system
try {
BufferedImage buf =
ImageIO.read(new File("f:/sourceImage.jpg"));
int width = buf.getWidth();
int height = buf.getHeight();
BufferedImage output = new BufferedImage(height, width, buf.getType());
Graphics2D g2d = (Graphics2D)output.getGraphics();
g2d.translate(height/2., width/2.);
g2d.rotate(Math.PI/2);
g2d.translate(-width/2., -height/2.);
g2d.drawImage(buf, 0,0,width, height,null);
ImageIO.write(output, "JPEG", new File("f:/rotatedImage.jpg"));
} catch (Exception e) {
e.printStackTrace();
}

How to define an offset for a PatternColor fill in iText?

I am trying to add tiled diagonal watermarks to the pdf, but it seems that pattern fills in iText are always tiled from the bottom left of the page, meaning that the tiles at the top and right side of the page can be cut abruptly. Is there an option to tile from the top left or with an offset instead?
Here is a sample of the code:
List<String> watermarkLines = getWatermarkLines();
Rectangle watermarkRect = getWatermarkRect();
PdfContentByte over = stamper.getOverContent(1);
PdfPatternPainter painter = over.createPattern(watermarkRect.getWidth(), watermarkRect.getHeight();
for (int x = 0; x < watermarkLines.size(); x++) {
AffineTransform trans = getWatermarkTransform(watermarkLines, x);
ColumnText.showTextAligned(painter, 0, watermarkLines.get(x), (float) trans.getTranslateX(), (float) trans.getTranslateY(), 45f);
}
over.setColorFill(new PatternColor(painter));
over.rectangle(0, 0, pageSize.getWidth(), pageSize.getHeight());
over.fill();
I tried changing the x and y of the rectangle function to negative or positive values, but it seems that the watermark is still stamped in the pattern as if it was tiled from the bottom left, cutting it in the same place as before.
First of, I cannot fathom which iText version you are using,
List<String> watermarkLines = getWatermarkLines();
...
ColumnText.showTextAligned(painter, 0, watermarkLines.get(x), (float) trans.getTranslateX(), (float) trans.getTranslateY(), 45f);
implies that the third parameter of the ColumnText.showTextAligned method you use is typed as String or Object. The iText 5 version I have at hand, though, requires a Phrase there. Below I'll show how to apply an offset with the current iText 5.5.13. You'll have to check whether it also works for your version.
Yes, you can apply an offset... in the pattern definition!
If instead of
PdfPatternPainter painter = over.createPattern(watermarkRect.getWidth(), watermarkRect.getHeight());
you create the pattern like this
PdfPatternPainter painter = over.createPattern(2 * watermarkRect.getWidth(), 2 * watermarkRect.getHeight(),
watermarkRect.getWidth(), watermarkRect.getHeight());
you have the same step size of pattern application (watermarkRect.getWidth(), watermarkRect.getHeight()) but a canvas twice that width and twice that height to position you text on. By positioning the text with an offset, you effectively move the whole pattern by that offset.
E.g. if you calculate the offsets as
Rectangle pageSize = pdfReader.getCropBox(1);
float xOff = pageSize.getLeft();
float yOff = pageSize.getBottom() + ((int)pageSize.getHeight()) % ((int)watermarkRect.getHeight());
and draw the text using
ColumnText.showTextAligned(painter, 0, new Phrase(watermarkLines.get(x)), (float) trans.getTranslateX() + xOff, (float) trans.getTranslateY() + yOff, 45f);
the pattern should fill the page as if starting at the top left corner of the visible page.
You haven't supplied getWatermarkLines, getWatermarkRect, and getWatermarkTransform. If I use
static AffineTransform getWatermarkTransform(List<String> watermarkLines, int x) {
return AffineTransform.getTranslateInstance(6 + 15*x, 6);
}
static Rectangle getWatermarkRect() {
return new Rectangle(65, 50);
}
static List<String> getWatermarkLines() {
return Arrays.asList("Test line 1", "Test line 2");
}
your original code for me creates a top left corner like this
and the code with the above offset creates one like this

how to get new coordinate after affine transformation using pdfbox in java

I have following pdf with crop box as shown below
Rotated the page to make it horizontal using below code
PDPageContentStream cs = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND, false, false);
PDRectangle cropBox = page.getCropBox();
float tx = (cropBox.getLowerLeftX() + cropBox.getUpperRightX()) / 2;
float ty = (cropBox.getLowerLeftY() + cropBox.getUpperRightY()) / 2;
cs.transform(Matrix.getTranslateInstance(tx, ty));
cs.transform(Matrix.getRotateInstance(Math.toRadians(5), 0, 0));
cs.transform(Matrix.getTranslateInstance(-tx, -ty));
cs.close();
The result from above code is
Since coordinates has been changed after affine transformation, for old crop box coordinates i am getting different section. I want to get the original section which i had pointed before rotation.
So,I have tried following techniques to get new coordinates, but didn't get the result
double x_transformed = (x*Math.cos(angle))-(y*Math.sin(angle));
double y_transformed = (x*Math.sin(angle))+(y*Math.cos(angle));
double X_transformed = (X*Math.cos(angle))-(Y*Math.sin(angle));
double Y_transformed = (X*Math.sin(angle))+(Y*Math.cos(angle));
Please suggest me solutions from which i can exactly crop the required section.
The data provided in the question is for reference only.Actual input files can get from below link :
drive.google.com/open?id=0BxPYWA8sfqTDVmY5YVQyZTZwSTA
Thanks in advance.
The issue is that you rotated the page around the center of the original crop box of the page (which defaults to the media box):
PDRectangle cropBox = page.getCropBox();
float tx = (cropBox.getLowerLeftX() + cropBox.getUpperRightX()) / 2;
float ty = (cropBox.getLowerLeftY() + cropBox.getUpperRightY()) / 2;
and thereafter you restrict to your new crop box:
int x = 39;
int y = 450;
int x2 = 360;
int y2= 500;
page.setCropBox(new PDRectangle(new BoundingBox((int)x, (int)y,(int)x2, (int)y2)));
In your previous question your task was to keep the center of the page crop box fixed and rotate everything around it. Thus, there it was correct to calculate the tx and ty from the page crop box.
Your task now, on the other hand, is to keep the center of the box fixed to which you eventually want to crop the page.
Thus, you now have to calculate tx and ty using the corners of that other box:
float tx = (x + x2) / 2;
float ty = (y + y2) / 2;
Alternatively you can simply change the order and first crop the page to the box between (x,y) and (x2,y2) and then rotate around the center of the changed crop box.
Yet another option would be to change the new crop box coordinates by the vector its center has been moved by the rotation.

SetPosition of an Image after Rotation with Affinetransform

I want to roatate an Image with Affinetransform
I did it like this:
AffineTransform at = AffineTransform.getTranslateInstance(image.getWidth(null), image.getHeight(null));
at.rotate(Math.toRadians(getRadian()),image.getWidth(null)/2, image.getHeight(null)/2);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(image, at, null);
But now I want to set the Position of the Image,how do I do this?
Thanks for help
First of all it's unclear which position of image you want to translate to necessary place. Let me propose general rule. Suppose that you want to be able to rotate image around its internal coordinates (ix,iy) and then place this internal position to new global place with coordinates (gx, gy). And rotation angle is "angleInRadians". Then your transformation will be:
AffineTransform at = AffineTransform.getTranslateInstance(gx, gy);
at.rotate(angleInRadians);
at.translate(-ix, -iy);
Do you see back order of events here? It's because of how transformation matrices are applied to each other and to position vector. If you read this from the end to beginning then what we do is we move internal position to coordinate start, then we rotate around this start and then we move this start to necessary global place.
If you need to move center of image then:
double ix = imageWidth / 2;
double iy = imageHeight / 2;
If you want to move left upper corner then ix = 0 and iy = 0, so you can skip at.translate(-ix, -iy) in this case.

Android Rotatable ImageView

I am trying to create a Rotatable an ImageView to which I will specify certain angle and pivot point and see it rotated around that pivot point. I tried something like this:
Matrix matrix = new Matrix();
matrix.postRotate(45, imageView.getWidth(), imageView.getHeight());
imageView.setScaleType(ScaleType.MATRIX);
imageView.setImageMatrix(matrix);
but the parameters of postRotate method (the second and third - the pivot points) make NO CHANGE at all. even if they are 0, 0 - it's the same thing.
So I wanna create a ImageView that would be rotated by certain angle when initialized. In this example 45 degrees. I tried setting the bounds and staff.. no help.
How do I do that? :/
You can rotate a ImageView by using setRotation(int);
// rotate imageView 45 around center pivot point
imageView.setPivotX(imageView.getWidth()/2);
imageView.setPivotY(imageView.getHeight()/2);
imageView.setRotation(45);
Reference: http://goo.gl/WhhGM
Edit: I had to shorten the link because of a ) in the url, some browsers don't like that.
This is how I use view.setRotation(float angle) in my apps, hope it will be helpful:
//to make rotation use next code
imageView.setPivotX(imageView.getWidth() / 2);
imageView.setPivotY(imageView.getHeight() / 2);
imageView.setRotation(45);
//to reset rotate state to initial position
imageView.setPivotX(imageView.getWidth() / 2);
imageView.setPivotY(imageView.getHeight() / 2);
imageView.setRotation(0);
Based on answer from Spencer
This function works for me.
public static Bitmap rotateImage (Bitmap srcBitmap, int width, int height, int rotation)
{
// create rotated image
Matrix matrix = new Matrix();
rotation = (rotation +1 ) % 3;
rotation = rotation * 90;
matrix.postRotate( rotation,
width,
height );
Bitmap rotatedBmp = Bitmap.createBitmap( srcBitmap,
0,
0,
srcBitmap.getWidth(),
srcBitmap.getHeight(),
matrix,
false );
return rotatedBmp;
}

Categories