How to translate image after this rotation transformation - java

This code below is my paintComponent for painting image objects, but while I want to be able rotate the image with out moving it about the center but also translate it according to a certain value.
trans.translate(xShift, yShift);
this is the line that I tried to use to translate my image, but it cuts off part of the image every time for some reason.
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (myImage != null) {
AffineTransform trans = new AffineTransform();
trans.translate(getWidth() / 2, getHeight() / 2);
trans.rotate(piece.getOrientation() * Math.PI / 2);
trans.translate(-myImage.getWidth() / 2, -myImage.getHeight() / 2);
trans.translate(xShift, yShift);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(myImage, trans, null);
}
}

My sense is that java has a problem with compounding transforms.
Maybe you can find another approach: e.g. transform the image itself, then apply a simple translation:
BufferedImage b22=new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2=(Graphics2D)b22.getGraphics();
AffineTransform trans = new AffineTransform();
trans.translate(getWidth() / 2, getHeight() / 2);
trans.rotate(Math.PI / 2);
trans.translate(-bim.getWidth() / 2, -bim.getHeight() / 2);
g2.drawImage(bim, trans, null);
AffineTransform trans2 = new AffineTransform();
trans2.translate(xoffset, yoffset);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(b22, trans2, null);
// or just g2d.drawImage(b22, xoffset, yoffset, null);
Of course it will cut of if you translate a certain extend.

Related

Printing in java doesn't complete in windows 7

When i print something by java application in windows 7 the output is blank page and the last graphic only is printed but when i print it in windows 10 it printed successfully .. so i don't no why this happen in windows 7 specially it was printing before on windows 7 and suddenly it happen what i told before (blank page)
this is my code and the output in the picture below
public void printed_bill_printing() {
totals_panelB.setVisible(true);
footer_panelB.setVisible(true);
int count_rows = tableEB.getRowCount();
int count = 0;
int table_height = 0;
while (count <= count_rows - 1) {
int row_height = tableEB.getRowHeight(count);
table_height = row_height + table_height;
count++;
}
float widtha = scrollPaneEB.getWidth();
float heighta = table_height + 30;
scrollPaneEB.setSize(Math.round(widtha), Math.round(heighta));
PrinterJob printJob = PrinterJob.getPrinterJob();
final int finalTable_height = table_height;
printJob.setPrintable(new Printable() {
#Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
if (pageIndex > 0) {
return Printable.NO_SUCH_PAGE;
}
Graphics2D paint_PF = (Graphics2D) graphics;
paint_PF.scale(.68, .6);
B.print(paint_PF);
Graphics2D paint_table = (Graphics2D) graphics;
paint_table.translate(1, 430);
paint_table.scale(.68, 1);
scrollPaneB.setVisible(false);
scrollPaneEB.print(paint_table);
Graphics2D paint_egmaly = (Graphics2D) graphics;
paint_egmaly.translate(1, finalTable_height + tableEB.getTableHeader().getHeight() + 2);
paint_egmaly.scale(1.45, 1);
totals_panelB.setVisible(false);
totals_panelB.print(paint_egmaly);
Graphics2D paint_tawke3 = (Graphics2D) graphics;
paint_tawke3.translate(0, 200);
footer_panelB.setVisible(false);
footer_panelB.print(paint_tawke3);
return Printable.PAGE_EXISTS;
}
});
PrintRequestAttributeSet printRequestAttrSet = new HashPrintRequestAttributeSet();
printRequestAttrSet.add(new MediaPrintableArea(0, 0, 350, 500, MediaPrintableArea.MM));
printRequestAttrSet.add(Chromaticity.MONOCHROME);
try {
PrintService ps = findPrintService(String.valueOf(printer1PST_combo.getSelectedItem()));
printJob.setPrintService(ps);
printJob.print(printRequestAttrSet);
} catch (PrinterException ex) {
}
adapt_table_size(scrollPaneEB, 440, 351);
}
Casting a Graphics object does not create a new Graphics object. You repeatedly cast the Graphics object and place it in new variables, but it’s still the same Graphics object, so your changes are cumulative.
Stepping through the code:
Graphics2D paint_PF = (Graphics2D) graphics;
This causes paint_PF to contain the same print Graphics object that was passed to the method. It is referring to the graphics object as a Graphics2D, but it’s still the same object.
paint_PF.scale(.68, .6);
B.print(paint_PF);
Now the original print Graphics object is at 0.68 by 0.6 scale.
Graphics2D paint_table = (Graphics2D) graphics;
Again, this is the same Graphics object, which the code just set to have a 0.68 by 0.6 scale.
paint_table.translate(1, 430);
paint_table.scale(.68, 1);
The print Graphics object is still scaled by 0.68 by 0.6; now you are scaling it further by 0.68, resulting in a Graphics object which is actually scaled by 0.04624 by 0.6 (because 0.68 × 0.68 = 0.04624).
scrollPaneB.setVisible(false);
scrollPaneEB.print(paint_table);
Graphics2D paint_egmaly = (Graphics2D) graphics;
paint_egmaly still contains the original print Graphics object.
paint_egmaly.translate(1, finalTable_height + tableEB.getTableHeader().getHeight() + 2);
paint_egmaly.scale(1.45, 1);
Now your print Graphics has been scaled, scaled again, translated, and scaled yet again.
totals_panelB.setVisible(false);
totals_panelB.print(paint_egmaly);
Graphics2D paint_tawke3 = (Graphics2D) graphics;
paint_tawke3 contains the original graphics object, with all of the previous scaling and translation.
paint_tawke3.translate(0, 200);
Now the Graphics object has been scaled, scaled, translated, scaled, and translated again.
footer_panelB.setVisible(false);
footer_panelB.print(paint_tawke3);
One way to make your changes to the Graphics temporary is by creating a new Graphics object, using Graphics.create, then apply your changes to that. If you do this, you are responsible for deallocating the Graphics object by calling its dispose method.
Graphics2D paint_PF = (Graphics2D) graphics.create();
paint_PF.scale(.68, .6);
B.print(paint_PF);
paint_PF.dispose(); // DO NOT FORGET THIS
Graphics2D paint_table = (Graphics2D) graphics.create();
paint_table.translate(1, 430);
paint_table.scale(.68, 1);
scrollPaneB.setVisible(false);
scrollPaneEB.print(paint_table);
paint_table.dispose(); // DO NOT FORGET THIS
Graphics2D paint_egmaly = (Graphics2D) graphics.create();
paint_egmaly.translate(1, finalTable_height + tableEB.getTableHeader().getHeight() + 2);
paint_egmaly.scale(1.45, 1);
totals_panelB.setVisible(false);
totals_panelB.print(paint_egmaly);
paint_egmaly.dispose(); // DO NOT FORGET THIS
Graphics2D paint_tawke3 = (Graphics2D) graphics.create();
paint_tawke3.translate(0, 200);
footer_panelB.setVisible(false);
footer_panelB.print(paint_tawke3);
paint_tawke3.dispose(); // DO NOT FORGET THIS
Another option, which uses fewer resources, is to restore the transform of the Graphics object after each change:
AffineTransform originalTransform = ((Graphics2D) graphics).getTransform();
Graphics2D paint_PF = (Graphics2D) graphics;
paint_PF.scale(.68, .6);
B.print(paint_PF);
paint_PF.setTransform(originalTransform);
Graphics2D paint_table = (Graphics2D) graphics;
paint_table.translate(1, 430);
paint_table.scale(.68, 1);
scrollPaneB.setVisible(false);
scrollPaneEB.print(paint_table);
paint_table.setTransform(originalTransform);
Graphics2D paint_egmaly = (Graphics2D) graphics;
paint_egmaly.translate(1, finalTable_height + tableEB.getTableHeader().getHeight() + 2);
paint_egmaly.scale(1.45, 1);
totals_panelB.setVisible(false);
totals_panelB.print(paint_egmaly);
paint_egmaly.setTransform(originalTransform);
Graphics2D paint_tawke3 = (Graphics2D) graphics;
paint_tawke3.translate(0, 200);
footer_panelB.setVisible(false);
footer_panelB.print(paint_tawke3);
paint_tawke3.setTransform(originalTransform);

Why is this stroke so fragmented and why does it only stroke the inside?

I'm drawing some text over an image using LineBreakMeasurer in conjunction with TextLayout but for some reason the stroke is only stroking the inside, and it's not very clean.
Here's an example of what I'm talking about:
http://i.imgur.com/eHtTw4p.png
And when I don't draw the letter over top and increase the stroke width, it actually will get thicker on the inside and not outside.
Here's my code:
float y = 0.0f;
float wrappingWidth = img.getWidth() * 0.8f;
LineBreakMeasurer measurer = new LineBreakMeasurer(str.getIterator(), imageGraphics.getFontRenderContext());
while (measurer.getPosition() < sentence.length()) {
TextLayout layout = measurer.nextLayout(wrappingWidth);
y += layout.getAscent();
float x = ((wrappingWidth * 0.8f) - layout.getVisibleAdvance()) / 2f + (wrappingWidth * 0.2f);
AffineTransform transform = new AffineTransform();
transform.translate((double)x, (double)y);
Shape outline = layout.getOutline(transform);
imageGraphics.setColor(Color.black);
imageGraphics.setClip(outline);
imageGraphics.setStroke(new BasicStroke(5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER));
imageGraphics.draw(outline);
imageGraphics.setColor(Color.white);
imageGraphics.setStroke(new BasicStroke());
layout.draw(imageGraphics, x, y);
y += layout.getDescent() + layout.getLeading();
}
I'm not sure what I'm doing wrong. Does anyone know?
Create another copy of the Graphics context before you draw the outline...
Graphics2D sg = (Graphics2D)imageGraphics.create();
sg.setColor(Color.black);
sg.setStroke(new BasicStroke(5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER));
sg.draw(outline);
sg.dispose();
I'd also get rid of the clip...
Instead of "stroking" the resulting shape, I'd be tempted to "fill" the background color and "draw" the outline color ontop of it, for example...
Graphics2D sg = (Graphics2D) g2d.create();
AffineTransform transform = new AffineTransform();
transform.translate((double) drawPosX, (double) drawPosY);
Shape outline = layout.getOutline(transform);
sg.setColor(Color.WHITE);
sg.fill(outline);
sg.setColor(Color.BLACK);
sg.draw(outline);
sg.dispose();
But if you want a "nice" thick stroke, use BasicStroke.JOIN_ROUND instead of BasicStroke.JOIN_MITER
Graphics2D sg = (Graphics2D) g2d.create();
AffineTransform transform = new AffineTransform();
transform.translate((double) drawPosX, (double) drawPosY);
Shape outline = layout.getOutline(transform);
sg.setStroke(new BasicStroke(5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
sg.setColor(Color.BLACK);
sg.draw(outline);
sg.dispose();

Inner-Transparent Selection Window in Java using GlassPane

I am trying to achieve the following
http://www.qksnap.com/i/3hunq/4ld0v/screenshot.png
I am currently able to draw rectangles successfully on a semi-transparent glasspane background using the following code:
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g.setColor(Color.black); // black background
g.fillRect(0, 0, frame.getWidth(), frame.getHeight());
g2.setColor(Color.GREEN.darker());
if (getRect() != null && isDrawing()) {
g2.draw(getRect()); // draw our rectangle (simple Rectangle class)
}
g2.dispose();
}
Which works great, however, I would love to have the area within the rectangle be completely transparent while the outside was still darken much like the screenshot above.
Any ideas?
..have the area within the rectangle be completely transparent while the outside was still darken much like the screenshot above.
Create a Rectangle (componentRect) that is the size of the component being painted.
Create an Area (componentArea) of that shape (new Area(componentRect)).
Create an Area (selectionArea) of the selectionRectangle.
Call componentArea.subtract(selectionArea) to remove the selected part.
Call Graphics.setClip(componentArea)
Paint the semi-transparent color.
(Clear the clipping area if more paint operations are required).
As Andrew has suggested (just beat me while I was finishing off my example)
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g.setColor(Color.black); // black background
Area area = new Area();
// This is the area that will filled...
area.add(new Area(new Rectangle2D.Float(0, 0, getWidth(), getHeight())));
g2.setColor(Color.GREEN.darker());
int width = getWidth() - 1;
int height = getHeight() - 1;
int openWidth = 200;
int openHeight = 200;
int x = (width - openWidth) / 2;
int y = (height - openHeight) / 2;
// This is the area that will be uneffected
area.subtract(new Area(new Rectangle2D.Float(x, y, openWidth, openHeight)));
// Set up a AlphaComposite
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
g2.fill(area);
g2.dispose();
}

Java, using AffineTransform not rotating exactly centered

I'm trying to rotate an image, but it's getting slightly messed up when I'm rotating it, and it looks like it's not rotating it on center. So if I go around it looks like it's being truncated. Is there a better method to get the "center" of the image?
public void RotateImageLeft() {
try {
BufferedImage newImage = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), originalImage.getType());
AffineTransform tx = new AffineTransform();
tx.rotate(Math.toRadians(-90.0), originalImage.getWidth() / 2, originalImage.getHeight() / 2);
Graphics2D g2 = newImage.createGraphics();
g2.drawImage(originalImage, tx, null);
originalImage = newImage;
this.repaint();
g2.dispose();
} catch (Exception ex) {
ex.toString();
}
//g2d.drawImage(getResImage(), rescale, x, y);
}
For full code disclosure, here's more code. Here's my painComponent overridden method:
public void paintComponent(Graphics g) {
super.paintComponent(g);
resizeImage();
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(getResImage(), rescale, x, y);
}
Here's the resizeImage() method that gets called:
public void resizeImage() {
Graphics g = getResImage().getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, getResImage().getWidth(), getResImage().getHeight());
int scaledWidth = (int) ((getOriginalImage().getWidth() * getHeight()
/ getOriginalImage().getHeight()));
if (scaledWidth < getWidth()) {
int leftOffset = getWidth() / 2 - scaledWidth / 2;
int rightOffset = getWidth() / 2 + scaledWidth / 2;
g.drawImage(getOriginalImage(),
leftOffset, 0, rightOffset, getHeight(),
0, 0, getOriginalImage().getWidth(), getOriginalImage().getHeight(),
null);
} else {
int scaledHeight = (getOriginalImage().getHeight() * getWidth())
/ getOriginalImage().getWidth();
int topOffset = getHeight() / 2 - scaledHeight / 2;
int bottomOffset = getHeight() / 2 + scaledHeight / 2;
g.drawImage(getOriginalImage(),
0, topOffset, getWidth(), bottomOffset,
0, 0, getOriginalImage().getWidth(), getOriginalImage().getHeight(),
null);
}
}
I'm using the ResizeImage method since I want any image to fit correctly on my 720/432 panel.
Here's some example pictures.
Pre-rotated
Post-rotated:
New code: (new image is the correct height/width of rotated image, still getting black bars. Screens below.
public void RotateImageLeft() {
try {
BufferedImage newImage = new BufferedImage( originalImage.getHeight(),originalImage.getWidth(), originalImage.getType());
AffineTransform tx = new AffineTransform();
tx.rotate(Math.toRadians(-90.0), newImage.getWidth() / 2, (newImage.getHeight() / 2));
Graphics2D g2 = newImage.createGraphics();
g2.drawImage(originalImage, tx, null);
originalImage = newImage;
this.repaint();
g2.dispose();
} catch (Exception ex) {
ex.toString();
}
}
Post rotate:
From my answer to another similar question
If you're rotating then this will work for 90 degrees.
move image so centered "around" the origin
plain rotate() call with no extra parameters
Move image back into the center remembering that now width = old height and height = old width.
Also remember the affine transform steps work in reverse order.
AffineTransform tx = new AffineTransform();
// last, width = height and height = width
tx.translate(originalImage.getHeight() / 2,originalImage.getWidth() / 2);
tx.rotate(Math.PI / 2);
// first - center image at the origin so rotate works OK
tx.translate(-originalImage.getWidth() / 2,-originalImage.getHeight() / 2);
If you want to rotate an image without cropping you need to add black bars around it first, since a rotated rectangle will always have a bigger bounding box than an axis-aligned one (exception: rotating a square by multiples of 90 degrees).
So what you want to do is do some trigonometric calculations beforehand to decide the maximum Width/Height of the rotated image, and combine that with the original Width/Height. Resize your image (centering it) using those dimensions, rotate it, and then crop it back to the Width/Height of the rotated image.

Rotating BufferedImage instances

I am having trouble getting a rotated BufferedImage to display. I think the rotation is working just fine, but I can't actually draw it to the screen. My code:
Class extends JPanel {
BufferedImage img;
int rotation = 0;
public void paintComponent(Graphics g) {
g.clearRect(0, 0, getWidth(), getHeight());
img2d = img.createGraphics();
img2d.rotate(Math.toRadians(rotation), img.getWidth() / 2, img.getHeight() / 2);
g.drawImage(img, imgx, imgy, null);
this.repaint();
}
}
This is not working for me. I could not find any way to draw the rotated img2d onto g.
EDIT: I have multiple objects that are being drawn onto g, so I can't rotate that. I need to be able to rotate things individually.
Maybe you should try using AffineTransform like this:
AffineTransform transform = new AffineTransform();
transform.rotate(radians, bufferedImage.getWidth() / 2, bufferedImage.getHeight() / 2);
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
bufferedImage = op.filter(bufferedImage, null);
Hope this helps.
I would use Graphics2D.drawImage(image, affinetranform, imageobserver).
The code example below rotates and translates an image to the center of the component. This is a screenshot of the result:
public static void main(String[] args) throws IOException {
JFrame frame = new JFrame("Test");
frame.add(new JComponent() {
BufferedImage image = ImageIO.read(
new URL("http://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png"));
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// create the transform, note that the transformations happen
// in reversed order (so check them backwards)
AffineTransform at = new AffineTransform();
// 4. translate it to the center of the component
at.translate(getWidth() / 2, getHeight() / 2);
// 3. do the actual rotation
at.rotate(Math.PI / 4);
// 2. just a scale because this image is big
at.scale(0.5, 0.5);
// 1. translate the object so that you rotate it around the
// center (easier :))
at.translate(-image.getWidth() / 2, -image.getHeight() / 2);
// draw the image
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(image, at, null);
// continue drawing other stuff (non-transformed)
//...
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
You are rotating the graphics for drawing into your image, not the image. Thats why you see no effect. Apply the rotation to the graphics you are painting on and it will draw the image rotated:
public void paintComponent(Graphics g) {
g.clearRect(0, 0, getWidth(), getHeight());
g.rotate(Math.toRadians(rotation), img.getWidth() / 2, img.getHeight() / 2);
g.drawImage(img, imgx, imgy, null);
this.repaint();
}
This will probably not draw entirely what you expect, the rotation will revolve around the coordinate origin. For the image to be rotate around its center you need to apply a coordinate translation before the rotation, for example:
g.translate(imgx >> 1, imgy >> 1);
The Graphics2D Tutorial has some more examples.
I know this question is old but I came up with a solution that has some advantages:
creates image of correct size.
correct offset.
does not unnecessarily rotate by 0° or 360°.
works for negative angles (e.g. -90°).
works when input is BufferedImage.TYPE_CUSTOM.
As it is, it is assumed that the angle is a multiple of 90°. The only improvement that one might need is to use an Enum for angle instead of just int.
Here's my code:
public static BufferedImage rotateBufferedImage(BufferedImage img, int angle) {
if (angle < 0) {
angle = 360 + (angle % 360);
}
angle %= 360;
if (angle == 0) {
return img;
}
final boolean r180 = angle == 180;
if (angle != 90 && !r180 && angle != 270)
throw new IllegalArgumentException("Invalid angle.");
final int w = r180 ? img.getWidth() : img.getHeight();
final int h = r180 ? img.getHeight() : img.getWidth();
final int type = img.getType() == BufferedImage.TYPE_CUSTOM ? BufferedImage.TYPE_INT_ARGB : img.getType();
final BufferedImage rotated = new BufferedImage(w, h, type);
final Graphics2D graphic = rotated.createGraphics();
graphic.rotate(Math.toRadians(angle), w / 2d, h / 2d);
final int offset = r180 ? 0 : (w - h) / 2;
graphic.drawImage(img, null, offset, -offset);
graphic.dispose();
return rotated;
}
public static BufferedImage rotateBufferedImage(String img, int angle) throws IOException {
return rotateBufferedImage(Paths.get(img), angle);
}
public static BufferedImage rotateBufferedImage(Path img, int angle) throws IOException {
return rotateBufferedImage(ImageIO.read(img.toFile()), angle);
}

Categories