Java RenderedImage subsection - java

I am trying to get a subsection of a RenderedImage in java. Say for example the image is 100x100 and I want the bottom right hand corner of that image so
RenderedImage i=...
x=49;
y=49;
width=50;
height=50;
RenderedImage i2=...

If your RenderedImage is a BufferedImage, you can simply use the getSubImage() method:
BufferedImage bi = ...;
BufferedImage bi2 = bi.getSubImage(x, y, width, height);
Note: bi2 will share the image data array with bi.
If your RenderedImage is not a BufferedImage, you have to do it the "harder" way:
WritableRaster raster = i.getData(new Rectangle(x, y, width, height))
.createCompatibleWritableRaster();
Hashtable<String,Object> properties = new Hashtable<String,Object>();
for (String name : i.getPropertyNames())
properties.put(name,i.getProperty(name));
// And finally creating a BufferedImage
// which of course implements RenderedImage:
RenderedImage i2 = new BufferedImage(i.getColorModel(), raster,
i.getColorModel().isAlphaPremultiplied(), properties);

Related

BufferedImage from 4-bit data buffer

Hello I have a problem with converting my 4-bit data buffer to WritableRaster.
Image resolution: 1024x768 (786432)
Here is description what I'm doing.
1) Create 4-bit BufferedImage
bit4Image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY, MY_BIT_4_COLOR_MODEL);
Graphics graphics = bit4Image.getGraphics();
graphics.drawImage(originalImage, 0, 0, null);
graphics.dispose();
//4-bit BufferedImage created. 4-bit BufferedImage is properly made cause it can be saved to hdd and looks good
2) Get byte array from DataBuffer from 4-bit
byte[] pixelData = ((DataBufferByte) bit4Image.getRaster().getDataBuffer()).getData();
// pixelData length is 393216
3) Now I want to create BufferedImage from this byte array pixelData
BufferedImage dest = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY, MY_BIT_4_COLOR_MODEL);
DataBufferByte buffer = new DataBufferByte(pixelData, pixelData.length);
WritableRaster raster = Raster.createInterleavedRaster(buffer, width, height, width, 1, new int[]{0}, new Point(0, 0));
dest.setData(raster);
Problem is when I call Raster.createInterleavedRaster. Exception:
java.awt.image.RasterFormatException: Data array too small (should be > 786431 )
I also tried something like this
BufferedImage dest = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY, MY_BIT_4_COLOR_MODEL);
dest.getRaster().setDataElements(0, 0, width, height, pixelData);
But this one gives me similar failure:
java.lang.ArrayIndexOutOfBoundsException: 393216
Could someone give me a hint or show the proper way of setting this 4-bit pixelData to WritableRaster?
Resolved.
I just had to create WritableRaster with giving it SampleModel:
SampleModel sm = MY_BIT_4_COLOR_MODEL.createCompatibleSampleModel(width, height);
WritableRaster wr = Raster.createWritableRaster(sm, buffer, new Point(0,0));
The initial code you had almost worked, the only problem is you tried to create an "interleaved" raster. For palette images (IndexColorModel) you typically have only one sample (the palette index) per pixel, so there's no samples to interleave.
Instead, your pixel data is 4 bit/pixel, stored as two pixels per byte. Storing more samples per storage unit, is often referred to as "packed". This means you need to create a "packed" raster, using one of the Raster.createPackedRaster methods.
Here's a full, runnable sample:
public static void main(String[] args) {
int width = 100;
int height = 100;
// Create initial 4 bit image
IndexColorModel icm = new IndexColorModel(4, 16, new int[16], 0, false, -1, DataBuffer.TYPE_BYTE);
BufferedImage bit4Image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY, icm);
// ...you probably do something in between here
// Get the pixel data
byte[] pixelData = ((DataBufferByte) bit4Image.getRaster().getDataBuffer()).getData();
// ...you probably do something in between here
// Create a data buffer around the array, wrap in raster
DataBufferByte buffer = new DataBufferByte(pixelData, pixelData.length);
WritableRaster raster = Raster.createPackedRaster(buffer, width, height, 4, null);
// Finally create a copy of the image, sharing pixel data
BufferedImage copy = new BufferedImage(icm, raster, icm.isAlphaPremultiplied(), null);
System.out.println("copy: " + copy);
}

Image quality reduces (turns reddish) as JPEG with BufferedImage

I am making a program where I extract out pixel array from an image, Take out ARGB values. And write them back again to make another image.
BufferedImage imagebuffer = ImageIO.read(new File("C:\\Users\\Ramandeep\\Downloads\\w3.jpg"));
iw = imagebuffer.getWidth();
ih = imagebuffer.getHeight();
pixels = new int[iw * ih];
PixelGrabber pg = new PixelGrabber(imagebuffer, 0, 0, iw, ih, pixels, 0, iw);
pg.grabPixels();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
image.setRGB(0, 0, width, height, pixels, 0, width);
ImageIO.write(image, "jpg", new File("C:\\Users\\Ramandeep\\Desktop\\out.jpg"));
ImageIO.write(image, "gif", new File("C:\\Users\\Ramandeep\\Desktop\\out.gif"));
ImageIO.write(image, "png", new File("C:\\Users\\Ramandeep\\Desktop\\out.png"));
Now output image for png and gif look fine but the output jpg image turns out quite reddish.
This is the original image
And this is the output jpg image
Any idea what might be causing this? Any push towards the right direction will be appreciated.
I dont know if this will work for you, but I always did it pixel-by-pixel.
So :
BufferedImage imagebuffer = ImageIO.read(new File("C:\\Users\\Ramandeep\\Downloads\\w3.jpg"));
iw = imagebuffer.getWidth();
ih = imagebuffer.getHeight();
BufferedImage image = new BufferedImage(iw,ih,BufferedImage.TYPE_INT_ARGB);
for (int x=0; x < iw; x++) {
for (int y=0; y < ih; y++) {
image.setRGB(x,y,imagebuffer.getRGB(x,y));
}
}
ImageIO.write(image, "jpg", new File("C:\\Users\\Ramandeep\\Desktop\\out.jpg"));
ImageIO.write(image, "gif", new File("C:\\Users\\Ramandeep\\Desktop\\out.gif"));
ImageIO.write(image, "png", new File("C:\\Users\\Ramandeep\\Desktop\\out.png"));
And it this way has a similar count of lines, so I think you could give it a try.
If you'd like to insert text, id ìmport java.awt.*;, what includes Graphics and Graphics2D and Font, and then :
Font font=new Font("Sans,0,20); //Name, type(none, bold, italic), size
Graphics2D imagegraphics=imagebuffer.createGraphics();
imagegraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //enable antialiasing
imagegraphics.setFont(font);
imagegraphics.setColor(Color.BLACK);
String yourtext="Fighter";
int h=imagegraphics.getFontMetrics().getHeight();
int w=imagegraphics.getFontMetrics().stringWidth(yourtext);
imagegraphics.drawString(yourtext,5,h); //Draw text upper left corner, note that y-value is the bottom line of the string
EDIT :
It was the Alpha value. Fixed by :
BufferedImage image = new
BufferedImage(iw,ih,BufferedImage.TYPE_INT_RGB); //RGB, jpeg hasnt got alpha, ints have been converted as if they contain red first, but its alpha(the first bytes, these ints are interpreted bitwise i think) (argb), so it became more red.

Convert color image into black and white using java created from scratch

I want to convert my picture from colored to Black and white which seems to be created from scratch.
Here is the code which i tried as described on the different post:
BufferedImage bi = ImageIO.read(new File("/Users/***/Documents/Photograph.jpg"));
ColorConvertOp op =
new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
ImageIO.write(bi, "PNG", new File("/Users/bng/Documents/rendered2.png"));
op.filter(bi, bi);
But still my image is not converted to the Black and white. Additionally, this code is increasing the rendered2.png image size to 10 folds.
Also, it would be great if i could find some Java 8 way of doing this.
Any suggestions?
Here is the code which worked for me:
BufferedImage input = ImageIO.read(new File("/Users/bng/Documents/Photograph.jpg"));
// Create a black-and-white image of the same size.
BufferedImage im = new BufferedImage(input.getWidth(), input.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
// Get the graphics context for the black-and-white image.
Graphics2D g2d = im.createGraphics();
// Render the input image on it.
g2d.drawImage(input, 0, 0, null);
// Store the resulting image using the PNG format.
ImageIO.write(im, "PNG", new File("/Users/bng/Documents/rendered.png"));
It was BufferedImage.TYPE_BYTE_BINARY which provided me the exact solution.
Lokking for the Java 8 Version for above code.
You have to find RGB of the existing colors of the image you want to change it.
Fyi, you want to change it as white RGB value is (255,255,255) and for black RGB value is (0,0,0)
Following method easily do the color change if you apply correct way of your requirement
private BufferedImage changeColor(BufferedImage image, int srcColor, int replaceColor)
{
BufferedImage destImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = destImage.createGraphics();
g.drawImage(image, null, 0, 0);
g.dispose();
for (int width = 0; width < image.getWidth(); width++)
{
for (int height = 0; height < image.getHeight(); height++)
{
if (destImage.getRGB(width, height) == srcColor)
{
destImage.setRGB(width, height, replaceColor);
}
}
}
return destImage;
}
you have to use the ColorConvertOp in a proper way:
create Source image
apply filter
save dest
example:
BufferedImage src = ImageIO.read(new File("/Users/***/Documents/Photograph.jpg"));
ColorConvertOp op =
new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
BufferedImage dest = op.filter(src, null);
ImageIO.write(dest, "PNG", new File("/Users/bng/Documents/rendered2.png"));
src:
dest:

How to obtain a resized BufferedImage

Say I have 2 TIF images and I read one of them into a BufferedImage instance:
ImageReader reader = ImageIO.getImageReadersByFormatName("tif").next();
reader.setInput(inputStream, false); // inputStream is the first image.
BufferedImage bufferedImage = reader.read(0);
Now I want to create a new BufferedImage without reading the other image. It should be the same as the previous one, but only different in size. imageType seems to be 0 for TIF images, but the following doesn't work.
BufferedImage largeBufferedImage = new BufferedImage(newWidth, newHeight, 0);
Is there any way to clone the existing BufferedImage and only change its size?
BTW I want to be able to do it for any image format. I don't want to deal with details like imageType if possible.
BufferedImage deepCopy(BufferedImage bi)/*method to clone BufferedImage*/ {
ColorModel cm = bi.getColorModel();
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
WritableRaster raster = bi.copyData(null);
return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
}
BufferedImage newImg = deepCopy(oldImg);//clone it
Graphics2D g = newImg.createGraphics();
g.drawImage(newImg, 0, 0, width, height, null);//newImg will be resized
When you draw in your paint method, you can add more parameters to stretch and scale image, see g.drawImage at this link.
After some trial and error, I found a working solution for my problem.
private BufferedImage copyAndResize(BufferedImage source, int width, int height)
{
ColorModel cm = source.getColorModel();
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
WritableRaster raster = source.copyData(null);
SampleModel sm = raster.getSampleModel().createCompatibleSampleModel(width, height);
WritableRaster newRaster = WritableRaster.createWritableRaster(sm, null);
BufferedImage newBi = new BufferedImage(cm, newRaster, isAlphaPremultiplied, null);
return newBi;
}

Find format of clipboard image in Java

I'm getting images from clipboard using this:
if(Toolkit.getDefaultToolkit().getSystemClipboard().isDataFlavorAvailable(DataFlavor.imageFlavor)){
ImageIcon IMG = new ImageIcon((BufferedImage) Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.imageFlavor));
}
Now I want to save this image in disk using ImageIO.write;
How can I find image format (JPG,PNG,GIF,...) to use in ImageIO.write as formatName ?
Thanks
The mime type of the content of the clipboard when checked via
.isDataFlavorAvailable(DataFlavor.imageFlavor)
is image/x-java-image (but OS vendors do not need to follow MIME types for clipboards).
I found two ways to supposedly get an image from a clipboard and write it to a file:
Using a helper method found in this blog post: The nightmares of getting images from the Mac OS X clipboard using Java.
Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard()
ImageIcon IMG = new ImageIcon((BufferedImage)
clip.getData(DataFlavor.imageFlavor));
BufferedImage bImage = getBufferedImage(IMG.getImage());
ImageIO.write(bImage, "png", new File("/tmp/test.png"));
The getBufferedImage method looks like this:
public static BufferedImage getBufferedImage(Image img) {
if (img == null) {
return null;
}
int w = img.getWidth(null);
int h = img.getHeight(null);
// draw original image to thumbnail image object and
// scale it to the new size on-the-fly
BufferedImage bufimg = new BufferedImage(w, h,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = bufimg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(img, 0, 0, w, h, null);
g2.dispose();
return bufimg;
}
Via Transferable. Note that this runs on OS X but produces an empty image of the correct size:
Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard()
Transferable content =
clip.getContents(null);
BufferedImage img = (BufferedImage) content.getTransferData(
DataFlavor.imageFlavor);
ImageIO.write(img, "png", new File("/tmp/test.png"));

Categories