The code below resizes a bitmap and keeps the aspect ratio.
I was wondering if there is a more efficient way of resizing, because i got the idea that i'm writing code that is already available in the android API.
private Bitmap resizeImage(Bitmap bitmap, int newSize){
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int newWidth = 0;
int newHeight = 0;
if(width > height){
newWidth = newSize;
newHeight = (newSize * height)/width;
} else if(width < height){
newHeight = newSize;
newWidth = (newSize * width)/height;
} else if (width == height){
newHeight = newSize;
newWidth = newSize;
}
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
width, height, matrix, true);
return resizedBitmap;
}
Use the method Bitmap.createScaledBitmap() :)
I really don't think so, I have done almost the same way as you, and got the idea from the android developer pages...
Depends on how you're using the image. If all you want to do is display the bitmap in a View, just call myImageView.setImageBitmap(bitmap) and let the framework resize it. But if you're concerned about memory, scaling first may be a good approach.
Related
I am looking to rotate an image that is loaded from files by 90 degrees. I have the code but when I use it, I am given an error saying that the coordinates are out of bounds. Any help would be appreciated.
Here is the method I have written so far:
public void rotateImage(OFImage image) {
if (currentImage != null) {
int width = image.getWidth();
int height = image.getHeight();
OFImage newImage = new OFImage(width, height);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
Color col = image.getPixel(i, j);
newImage.setPixel(height - j - 2, i, col);
}
}
image = newImage;
}
}
When you rotate the image by a certain angle, the resulting image becomes larger than the original one. The maximum image size is obtained when rotated by 45 degrees:
When creating a new image, you have to set its dimensions according to the rotated size:
public BufferedImage rotateImage(BufferedImage image, double angle) {
double radian = Math.toRadians(angle);
double sin = Math.abs(Math.sin(radian));
double cos = Math.abs(Math.cos(radian));
int width = image.getWidth();
int height = image.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);
// and so on...
return rotatedImage;
}
See also: Rotate a buffered image in Java
So I have a field where my image displays and my max height can be 375 and max width is 775. I want it to be as close to as one of these values as possible to get the maximum size while maintaining the aspect ratio This is what I came up with and it actually seems to work pretty well but I am thinking there is a better way I am not thinking of.
InputStream in = new ByteArrayInputStream(fileData);
BufferedImage buf = ImageIO.read(in);
int maxWidth = 775;
int maxHeight = 375;
int newWidth;
int newHeight;
float height = buf.getHeight();
float width = buf.getWidth();
float ratio = (float) 0.0;
if(height > maxHeight || width > maxWidth)
{
if (height > width)
{
ratio = (height/width);
}
else if(width > height)
ratio = (width/height);
while(height > maxHeight || width > maxWidth)
{
if (height > width)
{
height -= ratio;
width -= 1;
}
else if(width > height)
{
width -= ratio;
height -= 1;
}
}
}
newWidth = (int) width;
newHeight = (int) height;
// Call method to scale image to appropriate size
byte[] newByte = scale(fileData, newWidth, newHeight);
You know that you will use one of the two maxes (if you weren't the image could still be scaled up).
So it's just a problem of determining which. If this aspect ratio of the image is greater than your max area ratio, then width is your limiting factor, so you set width to max, and determine height from your ratio.
Same process can be applied for a smaller ratio
Code looks something like the following
float maxRatio = maxWidth/maxHeight;
if(maxRatio > ratio) {
width = maxWidth;
height = width / ratio;
} else {
height = maxHeight;
width = height * ratio;
}
I have an image where
Height = 1300
Width = 1300
I scaled the image to:
ScaledHeight = 700
ScaledWidth = 700
I am using the following to get the original Coordinates:
public Coordinate GetScaledXYCoordinate(int oldX, int oldY, int width, int height, int scaledWidth, int scaledHeight)
{
int newX = (int)(oldX * width)/scaledWidth;
int newY = (int)(oldY * height)/scaledHeight;
Coordinate retXY = new Coordinate(newX, newY);
return retXY;
}
EDIT:
I have updated to include answer
With
int width = 1300;
int scaledWidth = 700;
the value of (width/scaledWidth) is 1 - you are doing integer arithmetic not floating point.
Use
int newX = (oldX * width) /scaledWidth;
int newY = (oldY * height) /scaledHeight;
to avoid this issue.
I'm trying to scale an image in relation to the width/height. Here is my method:
private byte[] scaleImage(Bitmap image) {
byte[] image = new byte[]{};
int width= image.getWidth();
int height = image.getHeight();
int wh = width / height ;
int hw = height / width ;
int newHeight, newWidth;
if (width> 250 || height> 250) {
if (width> height) { //landscape-mode
newHeight= 250;
newWidth = Math.round((int)(long)(250 * wh));
Bitmap sizeChanged = Bitmap.createScaledBitmap(image, newWidth, newHeight, true);
int bytes = størrelseEndret.getByteCount();
ByteBuffer bb = ByteBuffer.allocate(bytes);
sizeChanged.copyPixelsFromBuffer(bb);
image = bb.array();
} else { //portrait-mode
newWidth = 250;
newHeight = Math.round((int)(long)(250 * hw));
...same
}
}
return image;
}
After that, I wrote some codes to convert the image from Bitmapto byte[] array, but after a Debug I noticed that I'm getting really weird values. For example:
width = 640, height = 480, but wh = 1, hw = 0, newHeight = 200 and newWidth = 200?! I simply don't understand why? what am I doing wrong? Any help or hints is very appreciate. Thanks, Carl
You're running into a problem of integer arithmetic, basically - you're performing a division to get a scaling factor, but as an integer - so for something like 640x480, the scaling factors would be 1 and 0, because 640/480 is 1, and 480/640 is 0.
Instead of handling this as (x1/y1)*y2, you can change it to (x1*y2)/y1 so that you perform the division afterwards. So long as you don't overflow the integer limit in the multiplication (unlikely here) it should be fine. So I'd rewrite your code as:
private byte[] scaleImage(Bitmap image) {
byte[] image = new byte[]{};
int width = image.getWidth();
int height = image.getHeight();
int newHeight, newWidth;
if (width > 250 || height > 250) {
if (width > height) { //landscape-mode
newHeight = 250;
newWidth = (newHeight * width) / height;
} else {
newWidth = 250;
newHeight = (newWidth * height) / width;
}
} else {
// Whatever you want to do here
}
// Now use newWidth and newHeight
}
(I would definitely separate the "calculating newWidth and newHeight" from "performing the scaling" if possible, to avoid repeated code.)
I need to put a random image inside a screen with given resolution (640x480, 1280x720, etc). I finished it in Java. In Android do not support the BufferedImage and Graphics2D, I wonder if there is a way to replace this code from Java to Android. Here is my code from Java:
public BufferedImage resizeImage(BufferedImage originalImage, int type){
BufferedImage resizedImage = new BufferedImage(screenWidth, screenHeight, type);
Graphics2D g = resizedImage.createGraphics();
int imgWidth = originalImage.getWidth();
int imgHeight = originalImage.getHeight();
int newImgWidth = 0;
int newImgHeight = 0;
int X = 0;
int Y = 0;
if (imgWidth > screenWidth){
// scale width to fit
newImgWidth = screenWidth;
//scale height to maintain aspect ratio
newImgHeight = (newImgWidth * imgHeight) / imgWidth;
}
if (newImgHeight > screenHeight) {
//scale height to fit instead
newImgHeight = screenHeight;
//scale width to maintain aspect ratio
newImgWidth = (newImgHeight * imgWidth) / imgHeight;
}
if (imgWidth < screenWidth && imgHeight < screenHeight) {
X = screenWidth/2 - imgWidth/2;
Y = screenHeight/2 - imgHeight/2;
g.drawImage(originalImage, X, Y, imgWidth, imgHeight, null);
g.dispose();
return resizedImage;
}
X = screenWidth/2 - newImgWidth/2;
Y = screenHeight/2 - newImgHeight/2;
g.drawImage(originalImage, X, Y, newImgWidth, newImgHeight, null);
g.dispose();
return resizedImage;
}
Thank you in advance!