I created a bufferedimage which i applied to a Rectangle to use as filling pattern to shape S. If i change S's position, the filling pattern changes with it instead of remaining "fixed". What could it be?
Image: (the pattern is a 3 stripes, all with the same aspect ratio) :alt text http://img88.imageshack.us/img88/8524/imageby.png
if (bannerPatternCreated == false) {
banner = new BufferedImage(size * 3, size * 3, BufferedImage.TYPE_INT_RGB);
Graphics2D gc = banner.createGraphics();
System.out.println("Creating banner...");
gc.setColor(Color.black);
gc.fillRect(0, 0, size, size * 3);
gc.setColor(Color.BLUE);
gc.fillRect(size, 0, size, size * 3);
gc.setColor(Color.WHITE);
gc.fillRect(size * 2, 0, size, size * 3);
gc.dispose();
bannerPatternCreated = true;
}
Rectangle patternPencil = new Rectangle(size, size);
g2.setPaint(new TexturePaint(banner, patternPencil));
Rectangle recto = new Rectangle(presentX-size, presentY-size, size, size);
g2.fill(recto);
It looks like the texture position is fixed, and so when you move recto around you're just getting a different view of the underlying infinitely-repeating texture.
If you change the patternPencil rect to be the same size/position as recto, I think it should get sorted:
Rectangle patternPencil = new Rectangle(presentX-size, presentY-size, size, size);
I think the TexturePaint docs indicate why the problem:
...the texture is anchored to the
upper left corner of a Rectangle2D
that is specified in user space.
Texture is computed for locations in
the device space by conceptually
replicating the specified Rectangle2D
infinitely in all directions
It's as if you're rectangle is drawn from 0,0 and replicated over and over, and the visible parts are small "windows" that are opened with the call to g2.fill.
If you're drawing to a canvas-type component, could you just use one of the Graphics.drawImage methods at the appropriate x,y?
Related
Original
https://drive.google.com/file/d/1B3xxfWkGsMs2_MQ_bUQ8_ALYI0DL-LIo/view?usp=sharing
When saved to file
https://drive.google.com/file/d/1z5euXupeHmiFebch4A39fVqGukoUiK0p/view?usp=sharing
When printed to canvas
https://drive.google.com/file/d/1VouD-ygf0pPXFFx9Knr4pv44FHMtoqcV/view?usp=sharing
BufferedImage temp = bImg.getSubimage(100, 100, (int)imgWidth - 100, (int)imgHeight - 100);
try{
ImageIO.write(temp, "png", new File("test.png"));
}catch(Exception e){
e.printStackTrace();
}
gc.drawImage(SwingFXUtils.toFXImage(temp, null), 100, 100);
For some reason if I print an image to the canvas, it is different than if I save the same image to a file. When I save it to a file it correctly calculates the subImage but when I print it to the canvas it disregards the x and y coords I give it and takes a subImage using (0,0) as (x,y) with the given width and height.
From the documentation of the getSubimage method:
Returns a subimage defined by a specified rectangular region. The returned BufferedImage shares the same data array as the original image.
The sub-image is just a “window” into the original image; they are using the same pixel data.
The SwingFXUtils.toFXImage documentation states:
Snapshots the specified BufferedImage and stores a copy of its pixels into a JavaFX Image object, creating a new object if needed.
While it would certainly make sense to only copy the pixels in the source image’s dimensions, the above words don’t make it completely clear that it won’t copy the entire pixel data buffer, thus ignoring the boundaries of a sub-image. I would consider this a bug, but I can see where there might be an argument that it’s not.
In the meantime, you can work around this by extracting a sub-image yourself:
BufferedImage cropped = new BufferedImage(
(int) imgWidth - 100,
(int) imgHeight - 100,
bImg.getType());
Graphics g = cropped.getGraphics();
g.drawImage(bImg, -100, -100, null);
g.dispose();
gc.drawImage(SwingFXUtils.toFXImage(cropped, null), 100, 100);
I would like to rotate, scale, and translate a section of an image. For example, I have a sprite-sheet with columns and rows of sprites. I can draw the section I want onto a temporary BufferedImage, then transform that temporary image onto the main graphics, but this is a very slow operation.
How can I make this much much faster? It needs to occur more than 100 * 60 times per second.
public void Draw_WorldSpace(Graphics2D g, double x, double y, double angle, double deltaTime) {
// setup portion of image to transform
BufferedImage tempImage = new BufferedImage(sourceRectangle.width, sourceRectangle.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = tempImage.createGraphics();
g2.drawImage(image, 0, 0, sourceRectangle.width, sourceRectangle.height, sourceRectangle.x, sourceRectangle.y, sourceRectangle.width, sourceRectangle.height, null);
g2.dispose();
// setup a transformation object
AffineTransform transform = new AffineTransform();
// match view rotation
transform.translate(GameLogic.viewPort.GetCanvasCenter().x, GameLogic.viewPort.GetCanvasCenter().y);
transform.rotate(Math.toRadians(GameLogic.viewPort.GetAngle()));
transform.translate(-GameLogic.viewPort.GetCanvasCenter().x, -GameLogic.viewPort.GetCanvasCenter().y);
// set to position
transform.translate(x - GameLogic.viewPort.GetViewPortCenter().x + GameLogic.viewPort.GetCanvasCenter().x, y - GameLogic.viewPort.GetViewPortCenter().y + GameLogic.viewPort.GetCanvasCenter().y);
// rotate
transform.rotate(Math.toRadians(angle));
// center on sprite
transform.translate(-sourceRectangle.width / 2, -sourceRectangle.height() / 2);
// draw the sprite
g.drawImage(tempImage, transform, null);
}
Ultimately I did what Hovercraft Full Of Eels suggested. I wasn't the biggest fan of the solution simply because it requires a lot of memory overhead. But ultimately, it worked like a charm and even game me more streamlined control over the graphics, so that's really cool.
Does anyone know whether libGDX has a method for scrolling/shifting an image/texture within itself?
To explain; I would like to be able to scroll the contents (pixels) of an image, either vertically or horizontally within its own region. For example, if an image is shifted 1 pixel to the right, all pixels move 1 to the right and those on the right-most-edge are wrapped to the left-most-edge. The image size does not change, only the positioning of the pixels within it change.
I have mainly been working with the Sprite class, it can do a lot (scale, rotate, etc) but shift/scroll as I need it, isn't there.
Before writting the method myself, I thought I'd ask here...
The following worked for me, this was provided by Kush:
float delta = 0f;
// In the Actors act method
delta += Gdx.graphics.getDeltaTime();
// Horizontal
batch.draw(texture, 0, 0, width, height, 0 + delta * 10, 1, 1 + delta * 10, 0);
// Vertical
batch.draw(texture, 0, 0, width, height, 1, 0 + delta * 10, 0, 1 + delta * 10);
You won't need Sprite for this, draw directly Texture using batch. For wrapping first set
Texture texture = new Texture("example.png");
texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
then draw using uv
batch.draw(texture, x, y, width, height, u, v, u2, v2);
or any other method that suits you in SpriteBatch.
The first "foo" is normal, but the second one is so huge I can only see the base of the "f". The font-size is the default.
BufferedImage image = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = image.createGraphics();
Shape ellipse = new Ellipse2D.Double(0, 0, 1.0, 1.0);
g2.setPaint(Color.RED);
g2.drawString("foo", 100, 100);
g2.scale(500.0f / length, 500.0f / length);
g2.drawString("foo", 1, 1);
Changing the font size will not help because it only allows int sizes and the size that would make sense for the scale is something like 0.02.
The reason I need to draw the text while in scaled space is because I am drawing a grid of nodes and I want to scale the coordinates to the number of nodes in each dimension. That way I do not have to do complicated calculations.
I need the text to label the edges.
Update: I am able to get the text by doing the following sequence each time I want to draw the text: saving the transform, translating to the desired location in scaled space, unscaling, drawing the text at (0, 0), and restoring the transform.
You can use Font method
public Font deriveFont(float size)
to obtain desired font size font. Guess the 0.02 shoud be fine.
I'm playing around with the 2.0.0-SNAPSHOT, and I want to set the page to landscape and also rotate my picture. So I've done page.setRotation(90);
There seems to be a bug with using PDFBox and AffineTransform
This code doesn't do anything like I'd expect:
AffineTransform at = new AffineTransform(w, 0, 0, h, 20, 20);
at.translate(0.5, 1);
at.rotate(Math.toRadians(90));
Width and Height have to be tiny to keep the image on the page, rotate by itself squishes the image, and translate before rotate seems to scale the image huge.
Is this a bug, or am I just not understanding PDFBox?
Don't do an extra translation, instead put the translation when creating the AT. Remember that the rotation is around the bottom-left axis, so add the width w to the x-position.
PDPage page = new PDPage();
document.addPage(page);
page.setRotation(90);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
int x = 150;
int y = 300;
// draw unrotated
contentStream.drawXObject(ximage, x, y, ximage.getWidth() / 2, ximage.getHeight() / 2);
// draw 90° rotated, placed on the right of the first image
AffineTransform at = new AffineTransform(ximage.getHeight() / 2, 0, 0, ximage.getWidth() / 2, x + ximage1.getWidth(), y);
at.rotate(Math.toRadians(90));
contentStream.drawXObject(ximage, at);
This will draw the image twice, once normally and once rotated 90°, and positioned to the right. "/2" is used to scale 50%, you can of course use another factor. Note that "/2" is not used for the initial x position, because the (scaled) width is needed twice. Once to position to the old position (because of the axis!), and once to move it to the right so that the images don't overlap.
Note also that getHeight() and getWidth() are reversed, for the page rotation.
AffineTransform at = new AffineTransform(w, 0, 0, h, 20, 20);
at.translate(0.5, 1);
at.rotate(Math.toRadians(90));
Width and Height have to be tiny to keep the image on the page, rotate by itself squishes the image, and translate before rotate seems to scale the image huge.
Is this a bug, or am I just not understanding PDFBox?
It is not a bug, it simply is math. You merely have to be aware that if you have an AffineTransform at and then call at.translate(...) or at.rotate(...), you do not set the translation / rotation part of the affine transformation to the given values but instead replace your transformation by the composition of the former transformation and the translation / rotation.
This means that e.g.
AffineTransform at = new AffineTransform(w, 0, 0, h, 20, 20);
at.translate(0.5, 1);
is not the same as
AffineTransform at = new AffineTransform(w, 0, 0, h, 20.5, 21);
as you might have expected, but instead
AffineTransform at = new AffineTransform(w, 0, 0, h, 20 + w/2, 20 + h);
This is why Width and Height have to be tiny to keep the image on the page - translate(0.5, 1) pushes very far otherwise.
As the order in which you compose the transformation matters, you might be happier if you created your transformation in this order:
AffineTransform at = AffineTransform.getTranslateInstance(0.5, 1);
at.rotate(Math.toRadians(90));
af.concatenate(new AffineTransform(w, 0, 0, h, 20, 20));
PS: As Tilman said: Remember that the rotation is around the bottom-left, so this composition will rotate off-screen, too. Simply add h+20 to the x coordinate of the initial translation.