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;
}
Related
I'm trying to copy in three new BufferedImage the same BufferedImage content, this is my code:
ColorModel cm = image.getColorModel();
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
WritableRaster raster = image.copyData(null);
BufferedImage[] images = {
new BufferedImage(cm, raster, isAlphaPremultiplied, null),
new BufferedImage(cm, raster, isAlphaPremultiplied, null),
new BufferedImage(cm, raster, isAlphaPremultiplied, null)
};
Even if I'm editing these images in distinct ways, the result is the same. I'm sure it's all ok because the code work properly if I have only one copy, but not more than one.
How can I manage something like this?
I got it. Even if I the BufferedImages are different, ColorModel and WritableRaster are only reference to the same objects.
If someone has my same problem try something like this:
private BufferedImage copyImage() {
ColorModel cm = image.getColorModel();
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
WritableRaster raster = image.copyData(null);
return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
}
public BufferedImage[] copyUpdatedImage() {
BufferedImage[] images = {
copyImage(),
copyImage(),
copyImage()
};
}
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);
}
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:
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);
I want to resize a .tiff file. I have used JAI toolkit to resize different types of images. Here is what I have tried to implement:
int imageWidth = 330;
int imageHeight = 490;
BufferedImage tempImage = new BufferedImage(imageWidth, imageHeight,BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = tempImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC);
graphics2D.drawImage(tempImage, 0, 0, imageWidth, imageHeight, null);
graphics2D.dispose();
File outfile = new File("D:/Work/YoursGallery/output.tif");
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(outfile));
FileSeekableStream ss = new FileSeekableStream("D:/Work/YoursGallery/sample1.tif");
ImageDecoder dec = ImageCodec.createImageDecoder("tiff", ss, null);
TIFFEncodeParam param = new TIFFEncodeParam();
param.setTileSize(tempImage.getWidth(), tempImage.getHeight());
TIFFImageEncoder encoder = (TIFFImageEncoder) TIFFCodec.createImageEncoder("tiff", out, param);
encoder.encode(dec.decodeAsRenderedImage());
out.close();
The image created is having same size as original image has. Can anyone please tell what is the issue?
Here is the sample tiff image which I am using to test it.
http://docs.google.com/fileview?id=0BxCDhEXNFvbeMTYyMGZmNDYtODhhNy00YWI3LTkxNDgtZTNhM2FhMjg5Y2Q3&hl=en&authkey=CPCEypgM
Thanks in advance.
That's because you are writing out tempImage which is still the original image.
graphics2D.drawImage(image, 0, 0, imageWidth, imageHeight, null);
change that to:
graphics2D.drawImage(tempImage, 0, 0, imageWidth, imageHeight, null);
or change your other code to write out image instead of tempImage
--Edit--
OK Attempt 2. Maybe having the source and destination the same is daft.
BufferedImage bsrc = ImageIO.read(new File(src));
BufferedImage bdest =
new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bdest.createGraphics();
AffineTransform at =
AffineTransform.getScaleInstance((double)width/bsrc.getWidth(),
(double)height/bsrc.getHeight());
g.drawRenderedImage(bsrc,at);
Try that :)
1) You are writing tempImage inside itself:
graphics2D.drawImage(tempImage, 0, 0, imageWidth, imageHeight, null);
Should be:
graphics2D.drawImage(originalImage, 0, 0, imageWidth, imageHeight, null);
2) You are writing the image that you just read (why are You reading it btw?):
encoder.encode(dec.decodeAsRenderedImage());
Should be:
encoder.encode(tempImage);