I am drawing some 2Dgraphics to JPanel.
I don't understant how to use scale if i change JPanelsize?
I have an image, which is composed of multiple lines and circles.
Is possible to compute a transformation and that multiply the values that miscalculation? How? Can you give me an example?
A neat way to do it (but not the best) is to have a final variable for the Width and Height, and everything is calculated based on those variables. then you could have a scale variable that is the size of the (JPanel / final Variable) and when you do g.draw() you can set the width to width * wScale, and the height to height * hScale. here is an example
public final WIDTH = 1080;
public final HEIGHT = WIDTH * 16 / 9;
private float wScale = 1;
private float hScale = 1;
public static void mainLoop()
{
wScale = jpanelWidth / (WIDTH * 1.0);
hScale = jpanelHeight / (HEIGHT * 1.0);
//makes the image to draw using the final width and height for calculations
someclass.makeImage(WIDTH, HEIGHT);
//gets an image that has the dimentions of WIDTH and HEIGHT
someimage = someclass.getImage();
//draws the image using its width and scales it to the actual size by multiplying it by the scaler
//the two zeros are at position (0, 0), and null is just the observer.
somegraphics.draw(someimage, 0, 0, (WIDTH * wScale), (HEIGHT * hScale), null);
}
if you need more information or have questions, you can ask for clarification, or contact me personally.
Related
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);
This question already has answers here:
Rotate a buffered image in Java
(4 answers)
Closed 1 year ago.
I'm trying to rotate the image around a reference point in Java using BufferedImage and AffineTransform, at first it seemed exactly what I needed, but it turns out it doesn't behave as expected. I need to do some rudimentary rotations, in multiples of 90, so I tried to do getQuadrantRotateInstance, but, if the reference point is at 0,0 then I get a RasterFormatException: Transformed height (0) is less than or equal to 0.
var rotation = switch (transform) {
case TRANS_NONE -> 0;
case TRANS_ROT90 -> 1;
case TRANS_ROT180 -> 2;
case TRANS_ROT270 -> 3;
default -> throw new NotImplementedException();
};
var transform = AffineTransform.getQuadrantRotateInstance(rotation, referenceX, referenceY);
var operation = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
var rotated = operation.filter(source, null);
By the looks of it the image gets rotated out of the canvas (into negative coordinates), resulting in exception above.
What would be the proper solution to create a rotated variant of the image without cropping or rotating around a center point like existing solutions do?
Rotating an image by an angle around the center point:
private BufferedImage rotateImage(BufferedImage buffImage, double angle) {
double radian = Math.toRadians(angle);
double sin = Math.abs(Math.sin(radian));
double cos = Math.abs(Math.cos(radian));
int width = buffImage.getWidth();
int height = buffImage.getHeight();
int nWidth = (int) Math.floor((double) width * cos + (double) height * sin);
int nHeight = (int) Math.floor((double) height * cos + (double) width * sin);
BufferedImage rotatedImage = new BufferedImage(nWidth, nHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = rotatedImage.createGraphics();
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
graphics.translate((nWidth - width) / 2, (nHeight - height) / 2);
// This is the rotation around the center point - change this line
graphics.rotate(radian, (double) (width / 2), (double) (height / 2));
graphics.drawImage(buffImage, 0, 0, null);
graphics.dispose();
return rotatedImage;
}
To change the origin point of the rotation see javadoc of the method rotate.
Source: Creating simple captcha.
What I want is might be separated into several or one methods, whatever is best.
I have four values that are set (as fields):
Width of image the whole image (canvas so to speak)
Height of the whole image (height of the canvas)
Padding (how many pixels I want to have as padding)
How many images in i want in the width and height separately (can be separate values)
What I want is to have a whole image, that I'm putting small images inside (these are the bitmap sizes I want to get from the method).
I basically want to have the size of the images inside, both the width and height.
And coordinates in of the small images in the whole image view.
A small example might be:
The width of the image is 200 and I want a padding of 4, and I want to have 3 images on one row of the image.
The calculation would might look like this:
(200 - (4*(3+1))) / 3 = 61,33;
The 3+1 is only because I want to have padding on either side of the small images.
But this is only for width, i would like to have a universal solution that applies to height as well.
And calculate the height and width of every image that is inside the canvas-image.
And just to put some sugar on top.
I would like to have the x and y coordinates of every image that is inside.
How can this be done?
And how do I get every value?
The bitmaps (I'm developing android) is stored in an ArrayList.
Basically I want this, a basic grid layout:
http://developer.android.com/images/ui/gridview.png
The values I have based on this image:
I have the size of the light-blue area,
including the space between the dark-blue images (padding)
and how many dark blue spots I want in every
row and column.
What I want is the size (width and height of the dark-blue spots),
and the coordinates of those images (where they should be placed in the light-blue area, x and y coordinates).
Anybody have a good solution for this?
UPDATED THE TEXT FOR CLARITY
This is the code of what I'm doing and wanted to do.
If anyone has ideas how to improve the code I will change my accepted answer.
public class ClassName {
public static int bitmapSizeWidth;
public static int bitmapSizeHeight;
public static final int bitmapPadding = 8;
public static final int howManyImagesColumn = 3;
public static final int howManyImagesRows = 2;
public static Bitmap folderBitmap(ArrayList<Bitmap> bitmapArray, int imageViewWidth, int imageViewHeight) {
bitmapSizeWidth = imageViewWidth;
bitmapSizeHeight = imageViewHeight;
Bitmap b = Bitmap.createBitmap(bitmapSizeWidth, bitmapSizeHeight, Bitmap.Config.RGB_565);
Canvas c = new Canvas(b);
//Lets do it in a set coordinate system now
if (bitmapArray.size() >= 1)
c.drawBitmap(bitmapArray.get(0), bitmapPadding, bitmapPadding, paint);
if (bitmapArray.size() >= 2)
c.drawBitmap(bitmapArray.get(1), calculateSecondCoord().xPos, bitmapPadding, paint);
if (bitmapArray.size() >= 3)
c.drawBitmap(bitmapArray.get(2), calculateThirdCoord().xPos, bitmapPadding, paint);
if (bitmapArray.size() >= 4)
c.drawBitmap(bitmapArray.get(3), bitmapPadding, calculateSecondCoord().yPos, paint);
if (bitmapArray.size() >= 5) {
c.drawBitmap(bitmapArray.get(4), calculateSecondCoord().xPos, calculateSecondCoord().yPos, paint);
}
if (bitmapArray.size() >= 6) {
c.drawBitmap(bitmapArray.get(5), calculateThirdCoord().xPos, calculateSecondCoord().yPos, paint);
}
return b;
}
public static BitmapSize calculateSingleBitmapSize(int imageViewWidth, int imageViewHeight) {
bitmapSizeWidth = imageViewWidth;
bitmapSizeHeight = imageViewHeight;
BitmapSize bsize = new BitmapSize();
bsize.widthSize = (int) (bitmapSizeWidth -
(bitmapPadding * (howManyImagesColumn + 1))) / howManyImagesColumn;
bsize.heightSize = (int) (imageViewHeight - (bitmapPadding * (howManyImagesRows + 1))) / howManyImagesRows;
return bsize;
}
/*
* First coord = padding
* Second coord (bitmapPadding) + calculateSingleBitmapSize(bitmapSizeWidth);
* Third coord (bitmapPadding * 3) + (calculateSingleBitmapSize(bitmapSizeWidth) * 2)
* The math is supposed to be correct but can perhaps be done in a more efficient way
*/
private static BitmapCoord calculateSecondCoord() {
BitmapCoord bCoord = new BitmapCoord();
bCoord.xPos = (int) (bitmapPadding * (howManyImagesColumn - 1)) + calculateSingleBitmapSize(bitmapSizeWidth, bitmapSizeHeight).widthSize;
bCoord.yPos = (int) (bitmapPadding * (howManyImagesRows)) + calculateSingleBitmapSize(bitmapSizeWidth, bitmapSizeHeight).heightSize;
return bCoord;
}
private static BitmapCoord calculateThirdCoord() {
BitmapCoord bCoord = new BitmapCoord();
bCoord.xPos = (int) (bitmapPadding * howManyImagesColumn) + calculateSingleBitmapSize(bitmapSizeWidth, bitmapSizeHeight).widthSize * 2;
bCoord.yPos = (int) (bitmapPadding * howManyImagesRows - 1) + calculateSingleBitmapSize(bitmapSizeWidth, bitmapSizeHeight).heightSize * 2;
return bCoord;
}
public static class BitmapSize {
public int widthSize;
public int heightSize;
}
static class BitmapCoord {
int xPos;
int yPos;
}
}
What you're describing is what game developers call spritesheets, tilesheets, tilesets, or whatever.
The general idea behind all of these is you have one image file of a certain type and inside that image you create subimages which can be pulled out and used individually in your program. Usually in video games these are of a consistent size but they don't have to be.
Check out the answer on this link: How to extract part of this image in Java? The answer here explains how to split an image up into several parts.
If you can't find what you're looking for there look up how game developers handle spritesheets for example to get an idea of how they do it.
I'm getting some strange values for the width/height in the following code, resulting in either a stretched picture, or no picture at all.
public void onSurfaceChanged(GL10 gl, int w, int h) {
screenHeight = h; // actual height in pixels
screenWidth = w; // actual width in pixels
worldWidth = 20; // width of the projection (20 units)
worldHeight = (int) (worldWidth * (screenHeight / screenWidth));
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glViewport(0, 0, screenWidth, screenHeight); //new viewport
gl.glLoadIdentity();
GLU.gluOrtho2D(gl, 0, worldWidth, 0, worldHeight); set the 2D projection
So I logged the variables, these are from portrait mode:
screenHeight = 455
screenWidth = 320
worldHeight = 20
worldWidth = 20
while (worldWidth * (screenHeight / screenWidth) should give 20*455/320=28 for worldHeight.
It gets even stranger in landscape mode, where worldHeight suddenly equals 0.
What am I doing wrong?
Let me guess, screenHeight and screenWidth are both ints? In this case the division will be an integer division, resulting in a rounded/truncated integer and therefore being 0 if the ratio is <1. Cast at least one of the operands of the division to a floating point number to perform a real floating point division:
worldHeight = (int) (worldWidth * ((float)screenHeight / (float)screenWidth));
I have the following Java class I've written for a LibGdx OpenGL project.
The camera keeps the aspect ratio of the screen no matter how you resize it by letterboxing either the top and bottom, or the sides. So far, so good.
The issue comes when I try to obtain the mouse x, y coordinates of a click, and the letterbox is involved for that axis.
First here is the class:
public class Camera {
private static float viewportWidth;
private static float viewportHeight;
private static float aspectRatio;
private static float barSize;
/**
* Creates an orthographic camera where the "play area" has the given viewport size. The viewport will be scaled to maintain the aspect ratio.
*
* #param virtualWidth the width of the game screen in virtual pixels.
* #param virtualHeight the height of the game screen in virtual pixels.
* #return the new camera.
*
*/
public static OrthographicCamera createCamera(float virtualWidth, float virtualHeight) {
aspectRatio = virtualWidth / virtualHeight;
float physicalWidth = Gdx.graphics.getWidth();
float physicalHeight = Gdx.graphics.getHeight();
if (physicalWidth / physicalHeight >= aspectRatio) {
// Letterbox left and right.
viewportHeight = virtualHeight;
viewportWidth = viewportHeight * physicalWidth / physicalHeight;
barSize = ????;
}
else {
// Letterbox above and below.
viewportWidth = virtualWidth;
viewportHeight = viewportWidth * physicalHeight / physicalWidth;
barSize = ????;
}
OrthographicCamera cam = new OrthographicCamera(viewportWidth , viewportHeight);
cam.position.set(virtualWidth / 2, virtualHeight / 2, 0);
cam.rotate(180, 1, 0, 0);
cam.update();
Gdx.app.log("BTLog", "barSize:"+barSize);
return cam;
}
public static float getViewportWidth() {
return viewportWidth;
}
public static float getViewportHeight() {
return viewportHeight;
}
}
LibGdx supplies me the x and y coordinates when an even happens, and I need to translate these raw coordinates into the scale of my camera (the virtual height and width).
When the screen is stretched (no letterboxing at all), it's pretty easy to obtain the x and y coordinates by using:
xRelative = (int) (x / (float)Gdx.graphics.getWidth() * Camera.getViewportWidth());
yRelative = (int) (y / (float)Gdx.graphics.getHeight() * Camera.getViewportHeight());
The problem is when the letterboxes come into play, it throws off the coordinate for that axis. I know I need to take into account the width of the letterboxing, but i'm having a hell of a time figuring how to calculate it.
Above where I have "barSize = ????;" my first instinct was to do this:
barSize = physicalHeight - viewportHeight; // to use height for example
Once I get the barSize, i'm fairly sure I can use this to get the right numbers (using the y axis for example):
yRelative = (int) (y / (float)Gdx.graphics.getHeight() * Camera.getViewportHeight() - Camera.getBarSize());
But the numbers don't match up. Any suggestions would be a really appreciated!
Ray ray = camera.getPickRay(x, y);
System.out.println(ray.origin.x);
System.out.println(ray.origin.y);