The code below generates a GIF image that’s half red and half blue.
How can I get one that’s half red and half transparent?
I’ve tried using the IndexColorModel constructor that takes a transparent pixel index as a parameter, and also changing the image type to IMAGE_TYPE_ARGB in the call to the BufferedImage constructor, but nothing is working for me.
int pixels[] = new int[90000];
for (int x = 0; x < 300; x++) {
for (int y = 0; y < 300; y++) {
pixels[(300 * y) + x] = (x < y) ? 1 : 0;
}
}
Color oneColor = Color.red;
Color anotherColor = Color.blue;
byte[] redMap = {(byte) (oneColor.getRed()), (byte) (anotherColor.getRed())};
byte[] greenMap = {(byte) (oneColor.getGreen()), (byte) (anotherColor.getGreen())};
byte[] blueMap = {(byte) (oneColor.getBlue()), (byte) (anotherColor.getBlue())};
IndexColorModel colorModel = new IndexColorModel(1, 2, redMap, greenMap, blueMap);
MemoryImageSource mis = new MemoryImageSource(300, 300, colorModel, pixels, 0, 300);
Image image = Toolkit.getDefaultToolkit().createImage(mis);
BufferedImage bufferedImage = new BufferedImage(300, 300, BufferedImage.TYPE_INT_RGB);
bufferedImage.getGraphics().drawImage(image, 0, 0, null);
try {
ImageIO.write(bufferedImage, "gif", new File("example.gif"));
} catch (IOException e) {
e.printStackTrace();
}
Turns out that BufferedImage.TYPE_BYTE_INDEXED is more appropriate for this case. This code does the trick:
Color oneColor = Color.blue;
Color anotherColor = Color.red;
byte[] redMap = {(byte) (oneColor.getRed()), (byte) (anotherColor.getRed())};
byte[] greenMap = {(byte) (oneColor.getGreen()), (byte) (anotherColor.getGreen())};
byte[] blueMap = {(byte) (oneColor.getBlue()), (byte) (anotherColor.getBlue())};
IndexColorModel colorModel = new IndexColorModel(1, 2, redMap, greenMap, blueMap, 0);
int transparency = colorModel.getTransparency();
int transparentPixel = colorModel.getTransparentPixel();
System.out.println("colorModel.getTransparency(): " + transparency);
System.out.println("colorModel.getTransparentPixel(): " + transparentPixel);
BufferedImage bufferedImage = new BufferedImage(300, 300, BufferedImage.TYPE_BYTE_INDEXED, colorModel);
WritableRaster writableRaster = bufferedImage.getRaster();
for (int x = 0; x < 300; x++) {
for (int y = 0; y < 300; y++) {
int[] fill = new int[1]; // A large block...
Arrays.fill(fill, (x < y) ? 0 : 1); // .. filled with one of the 7 first colors in the LUT.
writableRaster.setSamples(x, y, 1, 1, 0, fill);
}
}
In my experience, I changed the transparency of colors with alpha. For instance, transparent red looks like this:
Color transparentred = new Color (255, 0, 0, alpha);
Maybe try to set alpha for your redMap, blueMap, greenMap
Related
EDIT 3:
int rRows = result.length;
int rColums = result[0].length;
BufferedImage img = new BufferedImage(rColums, rRows, BufferedImage.TYPE_BYTE_GRAY);
for (int r = 0; r < rRows; r++) {
for (int t = 0; t < result[r].length; t++) {
img.setRGB(t, r, result[r][t]);
EDIT2:
Created the image like so....
BufferedImage img = new BufferedImage(rColums, rRows,BufferedImage.TYPE_BYTE_GRAY)
private static int[][] convertToArray(BufferedImage inputImage) {
final byte[] pixels = ((DataBufferByte) inputImage.getRaster().getDataBuffer()).getData();
final int width = inputImage.getWidth();
final int height = inputImage.getHeight();
System.out.println("height" + height + "width");
int[][] result = new int[height][width];
for (int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel++) {
int argb = 0;
argb = (int) pixels[pixel];
result[row][col] = argb;
col++;
if (col == width) {
col = 0;
row++;
}
}
return result;
Edit:
I've realized what I'm trying to ask is how to go from signed grayscale to unsigned grayscale, as I said adding 256 didnt work for me and also that would still seem to leave the image to dark as it wont raise the value of the +127 signed values to 256 unsigned.(hopefully I've expressed that correctly.
As per title I've an int[][] extracted from a buffered image via
((DataBufferByte) inputImage.getRaster().getDataBuffer()).getData()
The array ranges from -128 to 127. The problem is that when I attempt to reconstruct the image based on the int[][] by passing it to BufferedImage, it comes out too dark, and more like a black and white(mostly black) image.
I saw suggestion to add 256 to each sub zero value of the byte[] produced by the DataBufferByte, in the process of converting byte[] to in[][], but this actually produces a totally black image and I dont really get the logic of it, Like wouldnt you want to shift the entire scale over by 128, rather than just the negative numbers??
When you're writing your conversion. You have a signed byte, and you need to convert it to an ARGB int.
int unsignedByte = pixels[pixel]&0xff;
Now that isn't quite finished because we need it to be argb/grayscale.
argb = ( unsignedByte << 16 ) + ( unsignedByte << 8 ) + unsignedByte;
I've ignored the A part and just added rgb components. There is quite some documentation on this though.
Here is a complete example you can play with.
import java.awt.image.*;
import java.awt.*;
import javax.swing.*;
import java.util.HashSet;
import java.util.Set;
public class GrayScales{
public static void main(String[] args){
BufferedImage img = new BufferedImage( 256, 256, BufferedImage.TYPE_BYTE_GRAY );
Graphics g = img.createGraphics();
g.setColor( new Color( 128, 128, 128) );
g.fillOval( 32, 32, 192, 192 );
g.setColor( new Color( 255, 255, 255) );
g.fillOval( 96, 96, 64, 64 );
g.dispose();
BufferedImage dup = new BufferedImage( 256, 256, BufferedImage.TYPE_BYTE_GRAY );
byte[] pixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
Set<Integer> ints = new HashSet<>();
for(int i = 0; i<256; i++){
for(int j = 0; j<256; j++){
int px = (pixels[j*256 + i])&0xff;
ints.add(px);
int rgb = (px << 16) + (px << 8) + (px);
dup.setRGB(i, j, rgb);
}
}
System.out.println(ints);
JFrame frame = new JFrame("compare");
JLabel a = new JLabel( new ImageIcon( img ) );
JLabel b = new JLabel( new ImageIcon(dup) );
frame.add(a, BorderLayout.EAST);
frame.add(b, BorderLayout.WEST);
frame.pack();
frame.setVisible(true);
}
}
I need to display a PNG image in a SWT Java window, I'm using WindowBuilder and Eclipse.
First I tried with a label and this code:
Label lblNewLabel = new Label(this, SWT.NONE);
lblNewLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true, 1, 1));
Image image = new Image(display, "img/selae_mini.png");
lblNewLabel.setImage(image)
It worked when executing in eclipse, but when I generate the jar, then, it doesn't work. Then I found on Stack Overflow that you must use ClassLoader.getSystemClassLoader().getResourceAsStream to get a bufferedImage and after that you must convert that bufferedImage to a ImageData, and finally convert that into a SWT Image.
So I tried with this code:
protected Image readImage(String path, Display display) {
InputStream stream = ClassLoader.getSystemClassLoader().getResourceAsStream(path);
BufferedImage bi = null;
try {
bi = ImageIO.read(stream);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (stream != null)
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return new Image(display, convertToSWT(bi));
}
public static ImageData convertToSWT(BufferedImage bufferedImage) {
if (bufferedImage.getColorModel() instanceof DirectColorModel) {
DirectColorModel colorModel = (DirectColorModel) bufferedImage.getColorModel();
PaletteData palette = new PaletteData(
colorModel.getRedMask(),
colorModel.getGreenMask(),
colorModel.getBlueMask()
);
ImageData data = new ImageData(
bufferedImage.getWidth(),
bufferedImage.getHeight(), colorModel.getPixelSize(),
palette
);
WritableRaster raster = bufferedImage.getRaster();
int[] pixelArray = new int[3];
for (int y = 0; y < data.height; y++) {
for (int x = 0; x < data.width; x++) {
raster.getPixel(x, y, pixelArray);
int pixel = palette.getPixel(
new RGB(pixelArray[0], pixelArray[1], pixelArray[2])
);
data.setPixel(x, y, pixel);
}
}
return data;
} else if (bufferedImage.getColorModel() instanceof IndexColorModel) {
IndexColorModel colorModel = (IndexColorModel) bufferedImage.getColorModel();
int size = colorModel.getMapSize();
byte[] reds = new byte[size];
byte[] greens = new byte[size];
byte[] blues = new byte[size];
colorModel.getReds(reds);
colorModel.getGreens(greens);
colorModel.getBlues(blues);
RGB[] rgbs = new RGB[size];
for (int i = 0; i < rgbs.length; i++) {
rgbs[i] = new RGB(reds[i] & 0xFF, greens[i] & 0xFF, blues[i] & 0xFF);
}
PaletteData palette = new PaletteData(rgbs);
ImageData data = new ImageData(
bufferedImage.getWidth(),
bufferedImage.getHeight(),
colorModel.getPixelSize(),
palette
);
data.transparentPixel = colorModel.getTransparentPixel();
WritableRaster raster = bufferedImage.getRaster();
int[] pixelArray = new int[1];
for (int y = 0; y < data.height; y++) {
for (int x = 0; x < data.width; x++) {
raster.getPixel(x, y, pixelArray);
data.setPixel(x, y, pixelArray[0]);
}
}
return data;
}
return null;
}
The problem now is that my Image is a PNG file, and when doing the IF of the convertToSWT method, it gets that the image has a ColorModel called #pixelBits, so it returns null on that method! and I can't find any info about how to solve this problem.
I had this problem in before, and i resolved that. assuming your image has located in resource folder of your project:
String yourImg = "sampleImg.png";
...
Label swtImg = new Label(composite, SWT.NONE);
swtImg.setImage(new Image(display, YourClassName.calss.getResourceAsStream(yourImg)));
it's worked for me!
good luck ;)
I've seen many questions about this, but all of them are C#. None of them are Java, and I couldn't find a proper library for this.
What library can do this for me programmatically by giving it a string/hash? This algorithm is actually implemented on StackExchange.
You can look at this link. There is a code that you could use to generate your identicons http://www.davidhampgonsalves.com/Identicons
The code for Java is the following one:
public static BufferedImage generateIdenticons(String text, int image_width, int image_height){
int width = 5, height = 5;
byte[] hash = text.getBytes();
BufferedImage identicon = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
WritableRaster raster = identicon.getRaster();
int [] background = new int [] {255,255,255, 0};
int [] foreground = new int [] {hash[0] & 255, hash[1] & 255, hash[2] & 255, 255};
for(int x=0 ; x < width ; x++) {
//Enforce horizontal symmetry
int i = x < 3 ? x : 4 - x;
for(int y=0 ; y < height; y++) {
int [] pixelColor;
//toggle pixels based on bit being on/off
if((hash[i] >> y & 1) == 1)
pixelColor = foreground;
else
pixelColor = background;
raster.setPixel(x, y, pixelColor);
}
}
BufferedImage finalImage = new BufferedImage(image_width, image_height, BufferedImage.TYPE_INT_ARGB);
//Scale image to the size you want
AffineTransform at = new AffineTransform();
at.scale(image_width / width, image_height / height);
AffineTransformOp op = new AffineTransformOp(at, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
finalImage = op.filter(identicon, finalImage);
return finalImage;
}
I solved the problem.
I used Gravatar. I first got the link of the image and stored it as a String like this:
String identiconURL = "http://www.gravatar.com/avatar/" + userID + "?s=55&d=identicon&r=PG";
Then, I used Glide:
Glide.with(ProfilePictureChooserActivity.this)
.load(identiconURL)
.centerCrop()
.into(imageView);
I am getting the int array from png image how I will convert this to bufferdimage or creating new PNG file ?
int[] pixel = new int[w1*h1];
int i = 0;
for (int xx = 0; xx < h1; xx++) {
for (int yy = 0; yy < w1; yy++) {
pixel[i] = img.getRGB(yy, xx);
i++;
}
}
If you have an array of integers which are packed RGB values, this is the java code to save it to a file:
int width = 100;
int height = 100;
int[] rgbs = buildRaster(width, height);
DataBuffer rgbData = new DataBufferInt(rgbs, rgbs.length);
WritableRaster raster = Raster.createPackedRaster(rgbData, width, height, width,
new int[]{0xff0000, 0xff00, 0xff},
null);
ColorModel colorModel = new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
BufferedImage img = new BufferedImage(colorModel, raster, false, null);
String fname = "/tmp/whatI.png";
ImageIO.write(img, "png", new File(fname));
System.out.println("wrote to "+fname);
The reason for the arrays 0xff0000, 0xff00, 0xff is that the RGB bytes are packed with blue in the least significant byte. If you pack your ints different, alter that array.
You can rebuild the image manually, this is however a pretty expensive operation.
BufferedImage image = new BufferedImage(64, 64, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
for(int i = 0; i < pixels.size(); i++)
{
g.setColor(new java.awt.Color(pixels.get(i).getRed(), pixels.get(i).getGreen(), pixels.get(i).getBlue()));
g.fillRect(pixels.get(i).getxPos(), pixels.get(i).getyPos(), 1, 1);
}
try
{
ImageIO.write(image, "PNG", new File("imageName.png"))
}
catch(IOException error)
{
error.printStackTrace();
}
I formatted your image array into an object, this is personal preference tho (of course you could us an int array with this model as well). Keep in mind that you can always add the alpha to there as well.
Try the ImageIO class, which can take a byte array representing pixel data to build an image object and then writing it out in a particular format.
try {
BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(yourBytes));
ImageIO.write(bufferedImage, "png", new File("out.png"));
} catch (IOException e) {
e.printStackTrace();
}
I have two BufferedImages I loaded in from pngs. The first contains an image, the second an alpha mask for the image.
I want to create a combined image from the two, by applying the alpha mask. My google-fu fails me.
I know how to load/save the images, I just need the bit where I go from two BufferedImages to one BufferedImage with the right alpha channel.
I'm too late with this answer, but maybe it is of use for someone anyway. This is a simpler and more efficient version of Michael Myers' method:
public void applyGrayscaleMaskToAlpha(BufferedImage image, BufferedImage mask)
{
int width = image.getWidth();
int height = image.getHeight();
int[] imagePixels = image.getRGB(0, 0, width, height, null, 0, width);
int[] maskPixels = mask.getRGB(0, 0, width, height, null, 0, width);
for (int i = 0; i < imagePixels.length; i++)
{
int color = imagePixels[i] & 0x00ffffff; // Mask preexisting alpha
int alpha = maskPixels[i] << 24; // Shift blue to alpha
imagePixels[i] = color | alpha;
}
image.setRGB(0, 0, width, height, imagePixels, 0, width);
}
It reads all the pixels into an array at the beginning, thus requiring only one for-loop. Also, it directly shifts the blue byte to the alpha (of the mask color), instead of first masking the red byte and then shifting it.
Like the other methods, it assumes both images have the same dimensions.
I played recently a bit with this stuff, to display an image over another one, and to fade an image to gray.
Also masking an image with a mask with transparency (my previous version of this message!).
I took my little test program and tweaked it a bit to get the wanted result.
Here are the relevant bits:
TestMask() throws IOException
{
m_images = new BufferedImage[3];
m_images[0] = ImageIO.read(new File("E:/Documents/images/map.png"));
m_images[1] = ImageIO.read(new File("E:/Documents/images/mapMask3.png"));
Image transpImg = TransformGrayToTransparency(m_images[1]);
m_images[2] = ApplyTransparency(m_images[0], transpImg);
}
private Image TransformGrayToTransparency(BufferedImage image)
{
ImageFilter filter = new RGBImageFilter()
{
public final int filterRGB(int x, int y, int rgb)
{
return (rgb << 8) & 0xFF000000;
}
};
ImageProducer ip = new FilteredImageSource(image.getSource(), filter);
return Toolkit.getDefaultToolkit().createImage(ip);
}
private BufferedImage ApplyTransparency(BufferedImage image, Image mask)
{
BufferedImage dest = new BufferedImage(
image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = dest.createGraphics();
g2.drawImage(image, 0, 0, null);
AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.DST_IN, 1.0F);
g2.setComposite(ac);
g2.drawImage(mask, 0, 0, null);
g2.dispose();
return dest;
}
The remainder just display the images in a little Swing panel.
Note that the mask image is gray levels, black becoming full transparency, white becoming full opaque.
Although you have resolved your problem, I though I could share my take on it. It uses a slightly more Java-ish method, using standard classes to process/filter images.
Actually, my method uses a bit more memory (making an additional image) and I am not sure it is faster (measuring respective performances could be interesting), but it is slightly more abstract.
At least, you have choice! :-)
Your solution could be improved by fetching the RGB data more than one pixel at a time(see http://java.sun.com/javase/6/docs/api/java/awt/image/BufferedImage.html), and by not creating three Color objects on every iteration of the inner loop.
final int width = image.getWidth();
int[] imgData = new int[width];
int[] maskData = new int[width];
for (int y = 0; y < image.getHeight(); y++) {
// fetch a line of data from each image
image.getRGB(0, y, width, 1, imgData, 0, 1);
mask.getRGB(0, y, width, 1, maskData, 0, 1);
// apply the mask
for (int x = 0; x < width; x++) {
int color = imgData[x] & 0x00FFFFFF; // mask away any alpha present
int maskColor = (maskData[x] & 0x00FF0000) << 8; // shift red into alpha bits
color |= maskColor;
imgData[x] = color;
}
// replace the data
image.setRGB(0, y, width, 1, imgData, 0, 1);
}
For those who are using alpha in the original image.
I wrote this code in Koltin, the key point here is that if you have the alpha on your original image you need to multiply these channels.
Koltin Version:
val width = this.width
val imgData = IntArray(width)
val maskData = IntArray(width)
for(y in 0..(this.height - 1)) {
this.getRGB(0, y, width, 1, imgData, 0, 1)
mask.getRGB(0, y, width, 1, maskData, 0, 1)
for (x in 0..(this.width - 1)) {
val maskAlpha = (maskData[x] and 0x000000FF)/ 255f
val imageAlpha = ((imgData[x] shr 24) and 0x000000FF) / 255f
val rgb = imgData[x] and 0x00FFFFFF
val alpha = ((maskAlpha * imageAlpha) * 255).toInt() shl 24
imgData[x] = rgb or alpha
}
this.setRGB(0, y, width, 1, imgData, 0, 1)
}
Java version (just translated from Kotlin)
int width = image.getWidth();
int[] imgData = new int[width];
int[] maskData = new int[width];
for (int y = 0; y < image.getHeight(); y ++) {
image.getRGB(0, y, width, 1, imgData, 0, 1);
mask.getRGB(0, y, width, 1, maskData, 0, 1);
for (int x = 0; x < image.getWidth(); x ++) {
//Normalize (0 - 1)
float maskAlpha = (maskData[x] & 0x000000FF)/ 255f;
float imageAlpha = ((imgData[x] >> 24) & 0x000000FF) / 255f;
//Image without alpha channel
int rgb = imgData[x] & 0x00FFFFFF;
//Multiplied alpha
int alpha = ((int) ((maskAlpha * imageAlpha) * 255)) << 24;
//Add alpha to image
imgData[x] = rgb | alpha;
}
image.setRGB(0, y, width, 1, imgData, 0, 1);
}
Actually, I've figured it out. This is probably not a fast way of doing it, but it works:
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
Color c = new Color(image.getRGB(x, y));
Color maskC = new Color(mask.getRGB(x, y));
Color maskedColor = new Color(c.getRed(), c.getGreen(), c.getBlue(),
maskC.getRed());
resultImg.setRGB(x, y, maskedColor.getRGB());
}
}