convert WriteableImage to BufferedImage - java

I need some help concerning Writable- and BufferedImages in Java (11, Javafx):
How do I convert a WritabeImage to a BufferedImage? - WITHOUT using SwingFXUtils.fromFXImage()
It is important for me to find a solution without SwingFXUtils.fromFXImage(). I have already asked google, but the only results I am getting contain SwingFXUtils.fromFXImage(). So I am asking for your expertise.
Could you please help me?
Thanks!

Thanks for your help!
That is how my code looks like (including the 'SwingFXUtils' which I need to avoid):
static public void createImg(Node NODE, String name) {
WritableImage SNAPSHOT = NODE.snapshot(new SnapshotParameters(), null);
File file = new File(Properties.getSettingsPath() + File.separator + name + ".png");
try {
ImageIO.write(SwingFXUtils.fromFXImage(SNAPSHOT, null), "png", file);
} catch (IOException e) {
e.printStackTrace();
}
}

You can copy the pixels yourself:
BufferedImage convert(Image fxImage) {
int width = (int) Math.ceil(fxImage.getWidth());
int height = (int) Math.ceil(fxImage.getHeight());
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
int[] buffer = new int[width];
PixelReader reader = fxImage.getPixelReader();
WritablePixelFormat<IntBuffer> format =
PixelFormat.getIntArgbInstance();
for (int y = 0; y < height; y++) {
reader.getPixels(0, y, width, 1, format, buffer, 0, width);
image.getRaster().setDataElements(0, y, width, 1, buffer);
}
return image;
}

Related

Data too big for QR Code Generation with XZing in Android with Java

I am trying to generate a QR Code and set it to an ImageView out of a PGP Public Key in my Android Application with Java. The libary I use is XZing and I am on Android Studio.
This worked well before with smaller Strings, however when I try to do it with something as big as a PGP Public Key I get this error:
com.google.zxing.WriterException: Data too big
So my data is too big. Is there any possibility to create a QR Code with a String this big in XZing?
I have tried it with two different methods but both lead to the same exception.
Method one:
private void generateQR(String value) {
qrImage.setVisibility(View.VISIBLE);
QRGEncoder qrgEncoder = new QRGEncoder(value, null, QRGContents.Type.TEXT, 1000);
try {
// Getting QR-Code as Bitmap
Bitmap bm = qrgEncoder.encodeAsBitmap();
qrImage.setImageBitmap(bm);
// Setting Bitmap to ImageView
} catch (WriterException e) {
Log.v(TAG, e.toString());
}
}
Method two:
private Bitmap textToImage(String text, int width, int height) throws WriterException, NullPointerException {
BitMatrix bitMatrix;
try {
bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.DATA_MATRIX.QR_CODE,
width, height, null);
} catch (IllegalArgumentException Illegalargumentexception) {
return null;
}
int bitMatrixWidth = bitMatrix.getWidth();
int bitMatrixHeight = bitMatrix.getHeight();
int[] pixels = new int[bitMatrixWidth * bitMatrixHeight];
int colorWhite = 0xFFFFFFFF;
int colorBlack = 0xFF000000;
for (int y = 0; y < bitMatrixHeight; y++) {
int offset = y * bitMatrixWidth;
for (int x = 0; x < bitMatrixWidth; x++) {
pixels[offset + x] = bitMatrix.get(x, y) ? colorBlack : colorWhite;
}
}
Bitmap bitmap = Bitmap.createBitmap(bitMatrixWidth, bitMatrixHeight, Bitmap.Config.ARGB_4444);
bitmap.setPixels(pixels, 0, width, 0, 0, bitMatrixWidth, bitMatrixHeight);
return bitmap;
}
QR Codes have a max size.
I changed the error correction level to L and this then can fit in a longer URL.
This may work for you:
new MultiFormatWriter().encode(qrCodeText, BarcodeFormat.QR_CODE, width, height, mapWith(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L));

Java Grayscale Images

I've been working towards grayscaling images in java for some time. I was using a colorConvertOp, but it seems after a load of images were put through the process, eventually the JVM would hang in a locked state in the op.
Now I've started using:
BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_BYTE_GRAY);
Graphics g = image.getGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
However, I'm seeing a large spike in CPU, where it used to be under 20% and is now up to 120%. It also seems to be causing me memory leaks and eventually OOMs.
Is there an easier, quicker way to grayscale in java without using as much CPU/eliminates hanging from a JVM bug?
I wrote a java program to convert RGB image to GrayScaleImage. Hope this helps
public class GrayScale {
BufferedImage image;
int width;
int height;
public GrayScale() {
try {
File input = new File("input path of the image");
image = ImageIO.read(input);
width = image.getWidth();
height = image.getHeight();
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
Color c = new Color(image.getRGB(j, i));
int red = (int) (c.getRed() * 0.299);
int green = (int) (c.getGreen() * 0.587);
int blue = (int) (c.getBlue() * 0.114);
Color newColor = new Color(red + green + blue,
red + green + blue, red + green + blue);
image.setRGB(j, i, newColor.getRGB());
}
}
File ouptut = new File("output path of the image");
ImageIO.write(image, "jpg", ouptut);
} catch (Exception e) {
}
}
static public void main(String args[]) throws Exception {
GrayScale obj = new GrayScale();
}
}

Shift Image while keeping dimensions

I have an image that I would like to shift by some x, y value and then save. My problem is that I would like to keep my original dimensions, so that there is x and y "blank" space left after shifting my image.
Also, is there any way I can set the "blank" space to black?
Example: I shift a 600x600 image down by 45 and left by 30, so that the image is still 600x600 but the result has a 45 height and 30 width of "blank" space.
So far I have been using getSubimage method of BufferedImage to try and solve this but I cannot seem to return to the original dimensions.
Any ideas on how to solve this problem?
You could do that by creating a new buffered image and drawing on to it.
// Create new buffered image
BufferedImage shifted = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// Create the graphics
Graphics2D g = shifted.createGraphics();
// Draw original with shifted coordinates
g.drawImage(original, shiftx, shifty, null);
Hope this works.
public BufferedImage shiftImage(BufferedImage original, int x, int y) {
BufferedImage result = new BufferedImage(original.getWidth() + x,
original.getHeight() + y, original.getType());
Graphics2D g2d = result.createGraphics();
g2d.drawImage(original, x, y, null);
return result;
}
Should work.
Saving
public void SaveImage(BufferedImage image, String filename) {
File outputfile = new File(filename + ".png");
try {
ImageIO.write(image, "png", outputfile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

int array to BufferedImage

I'm making with the Robot class a printscreen and I convert the BufferedImage into an int array. Then I want to convert the int array back to a bufferedimage but that gives an error. This is my code:
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
BufferedImage printscreen = robot.createScreenCapture(new Rectangle(screen));
int[] pixels = ((DataBufferInt) printscreen.getRaster().getDataBuffer()).getData();
BufferedImage image = new BufferedImage(screen.width, screen.height, BufferedImage.TYPE_INT_RGB);
WritableRaster raster = (WritableRaster) image.getRaster();
raster.setPixels(0, 0, screen.width, screen.height, pixels);
But I get the error: ArrayIndexOutOfBoundsException: 2073600 but why?
I'm getting the exception on this line:
raster.setPixels(0, 0, screen.width, screen.height, pixels);
EDIT: It is working if I change the second bufferedimage type to TYPE_BYTE_GRAY.
int[] bitMasks = new int[]{0xFF0000, 0xFF00, 0xFF, 0xFF000000};
SinglePixelPackedSampleModel sm = new SinglePixelPackedSampleModel(
DataBuffer.TYPE_INT, width, height, bitMasks);
DataBufferInt db = new DataBufferInt(pixels, pixels.length);
WritableRaster wr = Raster.createWritableRaster(sm, db, new Point());
BufferedImage image = new BufferedImage(ColorModel.getRGBdefault(), wr, false, null);
Changed to:
getRaster().getPixels(0, 0, screen.width, screen.height, pixels)
and it works! Thanks for help anyway
The ArrayIndexOutOfBounds exception occurs as and when you try to access an element at index which is beyond the size of the array. In this case, you're passing the array to setPixels method, which accordingly to its javadocs doesn't explicitly check for the bounds or size of the array. So you should be doing that explicitly before calling that method. e.g.
if(x >= 0 && x < arr.length) {
// some code
}
This is the relevant code from SampleModel class used by WritableRaster.
public int[] getPixels(int x, int y, int w, int h,
int iArray[], DataBuffer data) {
int pixels[];
int Offset=0;
if (iArray != null)
pixels = iArray;
else
pixels = new int[numBands * w * h];
for (int i=y; i<(h+y); i++) {
for (int j=x; j<(w+x); j++) {
for(int k=0; k<numBands; k++) {
pixels[Offset++] = getSample(j, i, k, data);
}
}
}
return pixels;
}
The size of pixels in raster.setPixels(0, 0, screen.width, screen.height, pixels); should be width*height*3 when you set BufferedImage.TYPE_INT_RGB.
BufferedImage image = new BufferedImage(screen.width*3, screen.height,BufferedImage.TYPE_INT_RGB);
WritableRaster raster = (WritableRaster) image.getRaster();
raster.setPixels(0, 0, screen.width*3, screen.height, pixels);

Unable to create thumbnails for large image files

I am a newbie to graphics. I've been using this code to make thumbnails of image files. When i use small files(~100KB) like wall papers, it works fine but when i use an image file(a photo) of size ~5MB, it produces just a few bytes(~1-8KB) of file which shows up as black image. It does not matter what Width and Height i give it. What could be going wrong here? Is it a difference between image types or the camera that produces the images? I'm sure the problem images are from a different camera than the non problematic ones. I am giving quality param as 100 to not miss out any detail that way...
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
int dx = thumbWidth, dy = thumbHeight;
Image image = Toolkit.getDefaultToolkit().createImage(file);
MediaTracker mediaTracker = new MediaTracker(new Container());
mediaTracker.addImage(image, 0);
mediaTracker.waitForID(0);
double thumbRatio = (double)thumbWidth / (double)thumbHeight;
int imageWidth = image.getWidth(null);
int imageHeight = image.getHeight(null);
double imageRatio = (double)imageWidth / (double)imageHeight;
if (thumbRatio < imageRatio) {
thumbHeight = (int)(thumbWidth / imageRatio);
} else {
thumbWidth = (int)(thumbHeight * imageRatio);
}
if(thumbWidth > dx) {
thumbWidth = dx;
thumbHeight = (int)(thumbWidth / imageRatio);
}
if(thumbHeight > dy)
{
thumbHeight = dy;
thumbWidth = (int) (thumbHeight*imageRatio);
}
log.debug("X="+thumbWidth+" Y="+thumbHeight);
BufferedImage thumbImage = new BufferedImage(thumbWidth, thumbHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = thumbImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
graphics2D.drawImage(image, 0, 0, thumbWidth, thumbHeight, null);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(thumbImage);
quality = Math.max(0, Math.min(quality, 100));
param.setQuality((float)quality / 100.0f, false);
encoder.setJPEGEncodeParam(param);
encoder.encode(thumbImage);
log.debug("ThumbLength"+out.toByteArray().length);
FileOutputStream fos = new FileOutputStream("/root/testx.jpg");
fos.write(out.toByteArray());
fos.close();
} catch(Exception e) { log.debug(e.getMessage());}
return out.toByteArray();
You might try BufferedImage.TYPE_INT_ARGB, as shown here.
Also, your MediaTracker is waiting on the same thread; ImageIO.read() might be simpler.
Addendum: Also consider AffineTransformOp, although the src and dst must be different.

Categories