I want to read the image selected by user using JFileChooser and then be able to get the color Channels(R,G,B) and the width and height of the image.
Is this the right approach to read the selected image file.
File im1 = new File(chooser.getSelectedFile(), null);
BufferedImage buff =ImageIO.read(im1);
Or is there a better way to read the image file in order to get the values of its separate color channels and get its separate values.
Your code looks okay. Just keep going with width, height and RGB.
File im1 = chooser.getSelectedFile();
BufferedImage buff = ImageIO.read(im1);
if (buff != null) {
System.out.println(buff.getWidth() + " " + buff.getHeight());
System.out.println(buff.getRGB(0, 0));
}
I haven't found any 'better' way to load the image so I believe you're doing it right.
To answer your whole question, here's an example how to get specific color channels out of the image.
Color c = new Color(image.getRGB());
int red = c.getRed();
int green = c.getGreen();
int blue = c.getBlue();
Related
I am trying to load in a file from JFileChooser then convert it to BufferedImage to crop it. I am detecting the pixel colour of the image to determine where to crop. However, if I input a transparent image, the transparent portion will be considered black and output colour value (0, 0, 0, 255).
I used ImageIO to read the file from the file chooser into a buffered image.
inputFile = chooser.getSelectedFile();
// try and catch to see if file being read exist
try {
BufferedImage loadedImage = ImageIO.read(inputFile);
// the input image is a resized version of the loaded image to fit the button size
inputImage = CustomizationTool.resize(loadedImage, CustomizationTool.selectButtonDimension, CustomizationTool.selectButtonDimension);
// break the inputed word into characters
wordList = CustomizationTool.loadWord(loadedImage);
// loop through each character to crop the character from the file and resize it
for(int i = 0; i < wordList.size(); i++)
wordList.set(i, CustomizationTool.resize(
CustomizationTool.cropToFit(inputImage), CustomizationTool.selectButtonDimension, CustomizationTool.selectButtonDimension));
selectButton.setIcon(new ImageIcon(inputImage));
// fill the base variables in the lists for the input image
fillMatchingPixels();
} catch (IOException error) {
System.out.println("input file does not exsist");
}
I tried to print the transparency values using Color.getAlpha(). However, I got 255 as a result, which means it is completely opaque.
I'm trying to write a TIFF from a BufferedImage using Java Advanced Imaging (JAI), and am unsure of how to make it transparent. The following method works for making PNGs and GIFs transparent:
private static BufferedImage makeTransparent(BufferedImage image, int x, int y) {
ColorModel cm = image.getColorModel();
if (!(cm instanceof IndexColorModel)) {
return image;
}
IndexColorModel icm = (IndexColorModel) cm;
WritableRaster raster = image.getRaster();
int pixel = raster.getSample(x, y, 0);
// pixel is offset in ICM's palette
int size = icm.getMapSize();
byte[] reds = new byte[size];
byte[] greens = new byte[size];
byte[] blues = new byte[size];
icm.getReds(reds);
icm.getGreens(greens);
icm.getBlues(blues);
IndexColorModel icm2 = new IndexColorModel(8, size, reds, greens, blues, pixel);
return new BufferedImage(icm2, raster, image.isAlphaPremultiplied(), null);
}
But when writing a TIFF, the background is always white. Below is my code used for writing TIFF:
BufferedImage destination = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_BYTE_INDEXED);
Graphics imageGraphics = destination.getGraphics();
imageGraphics.drawImage(sourceImage, 0, 0, backgroundColor, null);
if (isTransparent) {
destination = makeTransparent(destination, 0, 0);
}
destination.createGraphics().drawImage(sourceImage, 0, 0, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
TIFFImageWriter writer = new TIFFImageWriter(new TIFFImageWriterSpi());
writer.setOutput(ios);
writer.write(destination);
I also do some metadata manipulation later as I'm actually dealing with GeoTIFF. But still the images are white at this point. While debugging, I can view the BufferedImage and it is transparent, but when i write the image, the file has a white background. Do I need to do something specific with TiffImageWriteParam? Thanks for any help you can provide.
TIFF has no option of storing transparency info (alpha channel) in the palette (as in your IndexedColorModel). The palette only supports RGB triplets. Thus, the fact that you set a color index to transparent is lost when you write the image to a TIFF.
If you need a transparent TIFF, your options are:
Use normal RGBA instead of indexed color (RGB, 4 samples/pixel, unassociated alpha). Just use BufferedImage.TYPE_INT_ARGB or TYPE_4BYTE_ABGR, probably. This will make the output file bigger, but is easy to implement, and should be more compatible. Supported by almost all TIFF software.
Save a separate transparency mask (a 1 bit image with photometric interpretation set to 4) with the palette image. Not sure if it supported by much software, some may display the mask as a separate b/w image. Not sure how this can be achieved in JAI/ImageIO, might require writing a sequence and setting some extra metadata.
Store a custom field containing the transparent index. Will not be supported by anything but your own software, but the file will still be compatible and displayed with the white (solid) background in other software. You should be able to set this using the TIFF metadata.
I try to draw an image from a bufferedImage into a PDF using PDFBox but fails, and I get black images and Acrobat Reader warns whith errors like "Out of memory" (but PDF is display).
I use a bufferedImage because I need to draw a JavaFX Image object (with came from call to Funciones.crearImagenDesdeTexto(), is a function which converts a text into an Image) into PDF. Rest of images works well without using bufferedimage.
PDPixelMap img = null;
BufferedImage bi;
try {
//If item has id, I try to get image with that id (image it's shows OK on PDF)
img = new PDPixelMap(documento, read(getClass().getResourceAsStream("/com/img/" + item.getId() + ".png")));
}
catch (Exception e) {
//If item has not id or fails load image, I create image on the fly (which contains item name. This not work on PDF, shows black images)
bi = new BufferedImage(alto, ancho, BufferedImage.TYPE_INT_ARGB);
bi.createGraphics().drawImage(SwingFXUtils.fromFXImage(Funciones.crearImagenDesdeTexto(item.getNombre()), null), ancho, alto, null);
img = new PDPixelMap(documento, bi);
}
finally {
contenedor.drawXObject(img, x, y, alto, ancho);
}
NOTE: crearImagenDesdeTexto() returns a JavaFX Image Object that is create on the fly (I try this function in other parts of the program and works well, function is take from other stackOverflow response).
Your code is confusing, you have three "new PDJpeg" and one of them is in a catch (which should just handle the error). And what does "read()" do? Does it pass a stream or a BufferedImage? If it is a stream, then it is wrong, because PDJpeg is for JPEGs, not for PNG.
The second one
img = new PDJpeg(documento, (getClass().getResourceAsStream("/com/img/" + Byte.toString(item.getId()) + ".png")));
is definitively wrong for the same reason: PDJPeg is not for PNG files / streams.
If you want to create an image from a PNG file / stream, use PDPixelMap.
It is possible to create a PDJpeg object from a BufferedImage, but this is recommended only if the image wasn't encoded before. Because if you would read a BufferedImage from a JPEG, and then use PDJPeg for this, you'll have a slight loss of quality as the image is decoded and encoded again (JPEG is a "lossy" compression format).
If my advice doesn't help, please upload the JPEG file and the PDF somewhere.
Also make sure that you're using the latest version, which is 1.8.7.
Update after comments:
the parameters to createGraphics.drawImage() should be 0, 0 and not width, height. The two parameters are a location, not a size.
Finally, I find a solution (thanks also to Tilman Hausherr):
private void dibujarImagen(Item i, int x, int y, int alto, int ancho) throws IOException {
PDPixelMap img = null;
try {
img = new PDPixelMap(documento, read(getClass().getResourceAsStream("/com/img/" + i.getId() + ".png")));
}
catch (IllegalArgumentException e) {
img = new PDPixelMap(documento, SwingFXUtils.fromFXImage(Funciones.crearImagenDesdeTexto(i.getNombre()),null));
}
finally {
contenedor.drawXObject(img, x, y, alto, ancho);
}
}
I am trying to save an image to JPEG. The code below works fine when image width is a multiple of 4, but the image is skewed otherwise. It has something to do with padding. When I was debugging I was able to save the image as a bitmap correctly, by padding each row with 0s. However, this did not work out with the JPEG.
Main point to remember is my image is represented as bgr (blue green red 1 byte each) byte array which I receive from a native call.
byte[] data = captureImage(OpenGLCanvas.getLastFocused().getViewId(), x, y);
if (data.length != 3*x*y)
{
// 3 bytes per pixel
return false;
}
// create buffered image from raw data
DataBufferByte buffer = new DataBufferByte(data, 3*x*y);
ComponentSampleModel csm = new ComponentSampleModel(DataBuffer.TYPE_BYTE, x, y, 3, 3*x, new int[]{0,1,2} );
WritableRaster raster = Raster.createWritableRaster(csm, buffer, new Point(0,0));
BufferedImage buff_image = new BufferedImage(x, y, BufferedImage.TYPE_INT_BGR); // because windows goes the wrong way...
buff_image.setData(raster);
//save the BufferedImage as a jpeg
try
{
File file = new File(file_name);
FileOutputStream out = new FileOutputStream(file);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(buff_image);
param.setQuality(1.0f, false);
encoder.setJPEGEncodeParam(param);
encoder.encode(buff_image);
out.close();
// or JDK 1.4
// ImageIO.write(image, "JPEG", out);
}
catch (Exception ex)
{
// Write permissions on "file_name"
return false;
}
I also looked on creating the JPEG in C++ but there was even less material on that, but it is still an option.
Any help greatly apprecieated.
Leon
Thanks for your suggestions, but I have managed to work it out.
To capture the image I was using WINGDIAPI HBITMAP WINAPI CreateDIBSection in C++, then OpenGL would draw to that bitmap. Unbeknown to be, there was padding added to the bitmap automatically the width was not a multiple of 4.
Therefore Java was incorrectly interpreting the byte array.
Correct way is to interpret bytes is
byte[] data = captureImage(OpenGLCanvas.getLastFocused().getViewId(), x, y);
int x_padding = x%4;
BufferedImage buff_image = new BufferedImage(x, y, BufferedImage.TYPE_INT_RGB);
int val;
for (int j = 0; j < y; j++)
{
for (int i = 0; i < x; i++)
{
val = ( data[(i + j*x)*3 + j*x_padding + 2]& 0xff) +
((data[(i + j*x)*3 + j*x_padding + 1]& 0xff) << 8) +
((data[(i + j*x)*3 + j*x_padding + 0]& 0xff) << 16);
buff_image.setRGB(i, j, val);
}
}
//save the BufferedImage as a jpeg
try
{
File file = new File(file_name);
FileOutputStream out = new FileOutputStream(file);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(buff_image);
param.setQuality(1.0f, false);
encoder.setJPEGEncodeParam(param);
encoder.encode(buff_image);
out.close();
}
The JPEG standard is extremely complex. I am thinking it may be an issue with padding the output of the DCT somehow. The DCT is done to transform the content from YCrCb 4:2:2 to signal space with one DCT for each channel, Y,Cr, and Cb. The DCT is done on a "Macroblock" or "minimum coded block" depending on your context. JPEG usually has 8x8 macroblocks. When on the edge and there are not enough pixel it clamps the edge value and "drags it across" and does a DCT on that.
I am not sure if this helps, but it sounds like a non standard conforming file. I suggest you use JPEGSnoop to find out more. There are also several explanations about how JPEG compression works.
One possibility is that the sample rate may be encoded incorrectly. It might be something exotic such as 4:2:1 So you might be pulling twice as many X samples as there really are, thus distorting the image.
it is an image I capture from the screen
Maybe the Screen Image class will be easier to use.
I am trying to write out a png file from a java.awt.image.BufferedImage. Everything works fine but the resulting png is a 32-bit file.
Is there a way to make the png file be 8-bit? The image is grayscale, but I do need transparency as this is an overlay image. I am using java 6, and I would prefer to return an OutputStream so that I can have the calling class deal with writing out the file to disk/db.
Here is the relevant portion of the code:
public static ByteArrayOutputStream createImage(InputStream originalStream)
throws IOException {
ByteArrayOutputStream oStream = null;
java.awt.Image newImg = javax.imageio.ImageIO.read(originalStream);
int imgWidth = newImg.getWidth(null);
int imgHeight = newImg.getHeight(null);
java.awt.image.BufferedImage bim = new java.awt.image.BufferedImage(imgWidth,
imgHeight, java.awt.image.BufferedImage.TYPE_INT_ARGB);
Color bckgrndColor = new Color(0x80, 0x80, 0x80);
Graphics2D gf = (Graphics2D)bim.getGraphics();
// set transparency for fill image
gf.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));
gf.setColor(bckgrndColor);
gf.fillRect(0, 0, imgWidth, imgHeight);
oStream = new ByteArrayOutputStream();
javax.imageio.ImageIO.write(bim, "png", oStream);
oStream.close();
return oStream;
}
The build in imageio png writer will write 32bit png files on all the platforms I have used it on, no matter what the source image is. You should also be aware that many people have complained that the resulting compression is much lower than what is possible with the png format. There are several independent png libraries available that allow you to specify the exact format, but I don't actually have any experience with any of them.
I found the answer as to how to convert RGBA to Indexed here: http://www.eichberger.de/2007/07/transparent-gifs-in-java.html
However, the resulting 8-bit png file only has 100% or 0% transparency. You could probably tweak the IndexColorModel arrays, but we have decided to make the generated file (what was an overlay mask) into an underlay jpg and use what was the static base as the transparent overlay.
It is an interesting question... It is late, I will experiment tomorrow. I will first try and use a BufferedImage.TYPE_BYTE_INDEXED (perhaps after drawing) to see if Java is smart enough to generate an 8bit PNG.
Or perhaps some image library can allow that.
[EDIT] Some years later... Actually, I made the code at the time, but forgot to update this thread... I used the code pointed at by Kat, with a little refinement on the handling of transparency, and saving in PNG format instead of Gif format. It works in making a 8-bit PNG file with all-or-nothing transparency.
You can find a working test file at http://bazaar.launchpad.net/~philho/+junk/Java/view/head:/Tests/src/org/philhosoft/tests/image/AddTransparency.java
using my ImageUtil class.
Since the code isn't that big, for posterity sake, I post it here, without the JavaDoc to save some lines.
public class ImageUtil
{
public static int ALPHA_BIT_MASK = 0xFF000000;
public static BufferedImage imageToBufferedImage(Image image, int width, int height)
{
return imageToBufferedImage(image, width, height, BufferedImage.TYPE_INT_ARGB);
}
public static BufferedImage imageToBufferedImage(Image image, int width, int height, int type)
{
BufferedImage dest = new BufferedImage(width, height, type);
Graphics2D g2 = dest.createGraphics();
g2.drawImage(image, 0, 0, null);
g2.dispose();
return dest;
}
public static BufferedImage convertRGBAToIndexed(BufferedImage srcImage)
{
// Create a non-transparent palletized image
Image flattenedImage = transformTransparencyToMagenta(srcImage);
BufferedImage flatImage = imageToBufferedImage(flattenedImage,
srcImage.getWidth(), srcImage.getHeight(), BufferedImage.TYPE_BYTE_INDEXED);
BufferedImage destImage = makeColorTransparent(flatImage, 0, 0);
return destImage;
}
private static Image transformTransparencyToMagenta(BufferedImage image)
{
ImageFilter filter = new RGBImageFilter()
{
#Override
public final int filterRGB(int x, int y, int rgb)
{
int pixelValue = 0;
int opacity = (rgb & ALPHA_BIT_MASK) >>> 24;
if (opacity < 128)
{
// Quite transparent: replace color with transparent magenta
// (traditional color for binary transparency)
pixelValue = 0x00FF00FF;
}
else
{
// Quite opaque: get pure color
pixelValue = (rgb & 0xFFFFFF) | ALPHA_BIT_MASK;
}
return pixelValue;
}
};
ImageProducer ip = new FilteredImageSource(image.getSource(), filter);
return Toolkit.getDefaultToolkit().createImage(ip);
}
public static BufferedImage makeColorTransparent(BufferedImage image, int x, int y)
{
ColorModel cm = image.getColorModel();
if (!(cm instanceof IndexColorModel))
return image; // No transparency added as we don't have an indexed image
IndexColorModel originalICM = (IndexColorModel) cm;
WritableRaster raster = image.getRaster();
int colorIndex = raster.getSample(x, y, 0); // colorIndex is an offset in the palette of the ICM'
// Number of indexed colors
int size = originalICM.getMapSize();
byte[] reds = new byte[size];
byte[] greens = new byte[size];
byte[] blues = new byte[size];
originalICM.getReds(reds);
originalICM.getGreens(greens);
originalICM.getBlues(blues);
IndexColorModel newICM = new IndexColorModel(8, size, reds, greens, blues, colorIndex);
return new BufferedImage(newICM, raster, image.isAlphaPremultiplied(), null);
}
}
Thanks for responding, I was going to try an TYPE_BYTE_INDEXED with an IndexColorModel and may still but if ImageIO writes out 32-bit regardless it appears that I may be wasting my time there.
The image I am trying to write out can be very large (up to 8000x4000) but is just a simple mask for the image underneath, so will only have a ~30% transparent gray and a 100% transparent cutout. I would use a GIF but IE6 seems to have trouble with displaying one that large.
It only gets generated once and in an internal set-up type screen, so performance isn't an issue either, but it does have to be done within the java code and not by an offline utility.
The libraries that you specified might be used to transform it while writing... I am going to go check that out.
If anyone has a better way, please let me know!!
Thanks!