How to scale an image using BlackBerry SDK API - java

Does anybody know why my image2 does not get scaled in the image2.scaleImage32() method?
Here's my code:
public ZoomScreen setScreen(){
map1.getBitmap().scaleInto(tempBmp, Bitmap.FILTER_BILINEAR);
Graphics g = Graphics.create(tempBmp); //works
g.drawBitmap(100, 100, bitmapImage2.getWidth(), bitmapImage2.getHeight(), bitmapImage2, 0, 0); //works
image2 = PNGEncodedImage.encode(tempBmp); //works
image3 = image2.scaleImage32(Fixed32.toFP(100), Fixed32.toFP(200)); // does not work
ZoomScreen screen = new ZoomScreen(image3);// works
return screen;
}

Perhaps you are passing absolute values of width and height to scaleImage32() method. But it is not a correct way to use this method. You need to pass scale factor instead of absolute value of width and height.
Assuming image is an EncodedImage class instance, and thumbnailSide is a side of scaled image in pixels, here is the code that should work for you:
final int currentWidthFixed32 = Fixed32.toFP(image.getWidth());
final int currentHeightFixed32 = Fixed32.toFP(image.getHeight());
final int thumbnailSideFixed32 = Fixed32.toFP(thumbnailSide);
final int scaleXFixed32 = Fixed32.div(currentWidthFixed32, thumbnailSideFixed32);
final int scaleYFixed32 = Fixed32.div(currentHeightFixed32, thumbnailSideFixed32);
image = image.scaleImage32(scaleXFixed32, scaleYFixed32);

Related

Bitmap drawn in a rectangle, now rotate 90 and scale it to the same rectangle

I have a Bitmap drawn in a rectangle. I want to rotate the Bitmap to 90 degree and draw the oriented Bitmap in the same rectangle bound, for that I may need to scale it.
Above the oriented image is not scaled to fit the rectangle bound of original rectangle (see the first image, the normal one) and also it does remove the lower part of the image. Below is code snippet. Any suggestion ?
sourceImageRect.left = 0;
sourceImageRect.top = 0;
sourceImageRect.right = bmp.getWidth();
sourceImageRect.bottom = bmp.getHeight();
destImageRect.top = destTop;
destImageRect.left = destLeft;
destImageRect.right = destLeft + destWidth;
destImageRect.bottom = destTop + destHeight;
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.rotate(90, (destLeft + (destWidth / 2)),
(destTop + (destHeight / 2)));
canvas.drawBitmap(bmp, sourceImageRect, destImageRect, null);
canvas.restore();
Last image is exact required output I need.
I writed a tool java class named ImageScaleUtil.java several days ago. Helping you can get some useful information on it.
You can use it, like this:
```java
Bitmap targetBitmap = ImageScaleUtil.getScaleBitmap(Bitmap sourceBitmap, int reqWidth, int reqHeight);
```
As of #pskink pastebin reference, following way I resolved and it's working code,
Matrix matrix = new Matrix();
matrix.postRotate(90);
Bitmap bmpRotated = Bitmap.createBitmap(bmpSource, 0, 0, bmpSource.getWidth(), bmpSource.getHeight(), matrix, true);
sourceImageRect.left = 0;
sourceImageRect.top = 0;
sourceImageRect.right = bmpRotated.getWidth();
sourceImageRect.bottom = bmpRotated.getHeight();
destImageRect.top = destTop;
destImageRect.left = destLeft;
destImageRect.right = destLeft + destWidth;
destImageRect.bottom = destTop + destHeight;
canvas.drawBitmap(bmpRotated, sourceImageRect, destImageRect, null);
However, I managed to create Bitmap outside of OnDraw()

How to get a region of interest from a SWT Image?

I want to get a region of interest (ROI) from an SWT Image object.
I am unable to find a method that will do this for me. Is it possible to avoid writing one by myself?
I need something like (similar to opencv implementations):
Image img = new Image(display, path);
Rectangle roi = new Rectangle(0, 0, 10, 10);
Image imgRoi = img.getROI(roi);
I'm not aware of a base SWT method to create images from a region, but I found a snippet that should do that here https://gist.github.com/azhawkes/4347761 (credits goes to the author Andy Hawkes).
Here I slightly modified the method to get in input the original image. I also implemented an optimization suggested by greg-449 (minimized the calls to Image.getImageData).
public static Image loadImageFromRegion(Image original, Rectangle region) {
ImageData originalImageData = original.getImageData();
ImageData data = new ImageData(region.width, region.height, originalImageData.depth, originalImageData.palette);
int[] pixels = new int[region.width];
byte[] alphas = new byte[region.width];
for (int y = 0; y < region.height; y++) {
originalImageData.getAlphas(region.x, region.y + y, region.width, alphas, 0);
originalImageData.getPixels(region.x, region.y + y, region.width, pixels, 0);
data.setPixels(0, y, region.width, pixels, 0);
data.setAlphas(0, y, region.width, alphas, 0);
}
return new Image(Display.getCurrent(), data);
}

Scaling an Image and positioning it at 0,0 in WPF

I have created BitMapSource from a list of RGBA pixels:
BitmapSource bmp = BitmapSource.Create(imageStrideInPixels, height, 96, 96, PixelFormats.Bgra32, null, imageData, imageStrideInPixels * pixelWidth);
I then create an image from the BitMapSource:
// create image and set image as source
Image BmpImg = new Image();
BmpImg.SetValue(Canvas.ZIndexProperty, 0);
BmpImg.Width = imageScaleWidth;
BmpImg.Height = imageScaleHeight;
BmpImg.Source = bmp;
I then add the Image to the Canvas:
mycanvas.Width = imageScaleWidth;
mycanvas.Height = imageScaleHeight;
mycanvas.Children.Clear();
mycanvas.Children.Add(BmpImg);
Canvas.SetLeft(BmpImg, 0); // to set position (x,y)
Canvas.SetTop(BmpImg, 0);
The problem is that it is not getting scaled to imageScaleWidth and imageScaleHeight, and it is being displayed half way down the canvas.
Note, I was able to do this in Java SWT by:
imageData = imageData.scaledTo(imageScaleWidth, imageScaleHeight);
gc.drawImage(imageData, 0, 0);
You can scale your image using a ScaleTransform:
// scale the original bitmap source
var transformedBitmap = new TransformedBitmap(
bmp,
new ScaleTransform(
imageScaleWidth / (double) bmp.PixelWidth,
imageScaleHeight / (double) bmp.PixelHeight));
// create image and set image as source
Image bmpImg = new Image();
bmpImg.SetValue(Canvas.ZIndexProperty, 0);
bmpImg.Source = transformedBitmap;
mycanvas.Width = imageScaleWidth;
mycanvas.Height = imageScaleHeight;
mycanvas.Children.Clear();
mycanvas.Children.Add(bmpImg);
Note that your image will be positioned at offset 0, 0 by default.
Instead of this
mycanvas.Children.Add(BmpImg);
Try this
mycanvas.Background = new VisualBrush(BmpImg);
This should render properly.
Are you sure the image is half way down the canvas and not the canvas itself is centered in its parent? I tested it and it appears that you can control the canvas position by setting vertical/horizontal alignment on canvas' parent. And also it scales properly when using the code you provided. However I created a BitmapSource in a different way. I used the following code:
PngBitmapDecoder decoder = new PngBitmapDecoder(new Uri(#"..."), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
BitmapSource bmp = decoder.Frames[0];

Finding the color at coordinates in a PNG image in Java

With a URL of a PNG image (or the data at that url, in String form), how could one use Java to find the RGB (or similar) value at a set of coordinates?
Thanks in advance!
This example should have all you need:
http://www.daniweb.com/software-development/java/threads/114513
To cite the relevant part of the thread:
File inputFile = new File("image.png");
BufferedImage bufferedImage = ImageIO.read(inputFile);
int w = bufferedImage.getWidth();
int h = bufferedImage.getHeight(null);
//Get Pixels
int [] rgbs = new int[w*h];
bufferedImage.getRGB(0, 0, w, h, rgbs, 0, w); //Get all pixels
and then to get a particular pixel, see the docs:
http://docs.oracle.com/javase/6/docs/api/java/awt/image/BufferedImage.html#getRGB(int,%20int,%20int,%20int,%20int%91%93,%20int,%20int)
i.e.:
int pixel = rgbs[offset + (y-startY)*scansize + (x-startX)];
If you just want one pixel, you can use getRGB(x, y):
http://docs.oracle.com/javase/6/docs/api/java/awt/image/BufferedImage.html#getRGB(int,%20int)
i.e.:
int pixel = bufferedImage.getRGB(x, y);

Java BufferedImage alternatives

I am trying to implement a simple class that will allow a user to crop an image to be used for their profile picture. This is a java web application.
I have done some searching and found that java.awt has a BufferedImage class, and this appears (at first glance) to be perfect for what I need. However, it seems that there is a bug in this (or perhaps java, as I have seen suggested) that means that the cropping does not always work correctly.
Here is the code I am using to try to crop my image:
BufferedImage profileImage = getProfileImage(form, modelMap);
if (profileImage != null) {
BufferedImage croppedImage = profileImage
.getSubimage(form.getStartX(), form.getStartY(), form.getWidth(), form.getHeight());
System.err.println(form.getStartX());
System.err.println(form.getStartY());
File finalProfileImage = new File(form.getProfileImage());
try {
String imageType = getImageType(form.getProfileImage());
ImageIO.write(croppedImage, imageType, finalProfileImage);
}
catch (Exception e) {
logger.error("Unable to write cropped image", e);
}
}
return modelAndView;
}
protected BufferedImage getProfileImage(CropImageForm form, Map<String, Object> modelMap) {
String profileImageFileName = form.getProfileImage();
if (validImage(profileImageFileName) && imageExists(profileImageFileName)) {
BufferedImage image = null;
try {
image = getCroppableImage(form, ImageIO.read(new File(profileImageFileName)), modelMap);
}
catch (IOException e) {
logger.error("Unable to crop image, could not read profile image: [" + profileImageFileName + "]");
modelMap.put("errorMessage", "Unable to crop image. Please try again");
return null;
}
return image;
}
modelMap.put("errorMessage", "Unable to crop image. Please try again.");
return null;
}
private boolean imageExists(String profileImageFileName) {
return new File(profileImageFileName).exists();
}
private BufferedImage getCroppableImage(CropImageForm form, BufferedImage image, Map<String, Object> modelMap) {
int cropHeight = form.getHeight();
int cropWidth = form.getWidth();
if (cropHeight <= image.getHeight() && cropWidth <= image.getWidth()) {
return image;
}
modelMap.put("errorMessage", "Unable to crop image. Crop size larger than image.");
return null;
}
private boolean validImage(String profileImageFileName) {
String extension = getImageType(profileImageFileName);
return (extension.equals("jpg") || extension.equals("gif") || extension.equals("png"));
}
private String getImageType(String profileImageFileName) {
int indexOfSeparator = profileImageFileName.lastIndexOf(".");
return profileImageFileName.substring(indexOfSeparator + 1);
}
The form referred to in this code snippet is a simple POJO which contains integer values of the upper left corner to start cropping (startX and startY) and the width and height to make the new image.
What I end up with, however, is a cropped image that always starts at 0,0 rather than the startX and startY position. I have inspected the code to make sure the proper values are being passed in to the getSubimage method, and they appear to be.
Are there simple alternatives to using BufferedImage for cropping an image. I have taken a brief look at JAI. I would rather add a jar to my application than update the jdk installed on all of the production boxes, as well as any development/testing servers and local workstations.
My criteria for selecting an alternative are:
1) simple to use to crop an image as this is all I will be using it for
2) if not built into java or spring, the jar should be small and easily deployable in a web-app
Any suggestions?
Note: The comment above that there is an issue with bufferedImage or Java was something I saw in this posting: Guidance on the BufferedImage.getSubimage(int x, int y, int w, int h) method?
I have used getSubimage() numerous times before without any problems. Have you added a System.out.println(form.getStartX() + " " + form.getStartY()) before that call to make sure they're not both 0?
Also, are you at least getting an image that is form.getWidth() x form.getHeight()?
Do make sure you are not modifying/disposing profileImage in any way since the returned BufferedImage shares the same data array as the parent.
The best way is to just simply draw it across if you want a completely new and independent BufferedImage:
BufferedImage croppedImage = new BufferedImage(form.getWidth(),form.getHeight(),BufferedImage.TYPE_INT_ARGB);
Graphics g = croppedImage.getGraphics();
g.drawImage(profileImage,0,0,form.getWidth(),form.getHeight(),form.getStartX(),form.getStartY(),form.getWidth(),form.getHeight(),null);
g.dispose();
You can do it in this manner as well (code is not 100% tested as I adopted for example from an existing app i did):
import javax.imageio.*;
import java.awt.image.*;
import java.awt.geom.*;
...
BufferedImage img = ImageIO.read(imageStream);
...
/*
* w = image width, h = image height, l = crop left, t = crop top
*/
ColorModel dstCM = img.getColorModel();
BufferedImage dst = new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(w, h), dstCM.isAlphaPremultiplied(), null);
Graphics2D g = dst.createGraphics();
g.drawRenderedImage(img, AffineTransform.getTranslateInstance(-l,-t));
g.dispose();
java.io.File outputfile = new java.io.File(sessionScope.get('absolutePath') + java.io.File.separator + sessionScope.get('lastUpload'));
ImageIO.write(dst, 'png', outputfile);
Thanks for all who replied. It turns out that the problem was not in the cropping code at all.
When I displayed the image to be cropped, I resized it to fit into my layout nicely, then used a javascript cropping tool to figure out the coordinates to crop.
Since I had resized my image, but didn't take the resizing into account when I was determining the cropping coordinates, I ended up with coordinates that appeared to coincide with the top left corner.
I have changed the display to no longer resize the image, and now cropping is working beautifully.

Categories