I'm trying to draw 2 images, one on top of the other. The 1'st image is an arrow (that should appear like a header in the final image). The 1'st image (arrow) is 32x32 px while the 2'nd is 24x24.
Ideally I would like to draw the 2'nd image on top of the 1'st, starting from the right-bottom corner of the 1'st image.
Currently I'm using such code
// load source images
BufferedImage baseImage = ImageIO.read(new File(baseImg.getFileLocation()));
BufferedImage backgroundImage = ImageIO.read(new File(backgroundImg.getFileLocation()));
// create the new image, canvas size is the max. of both image sizes
int w = Math.max(baseImage.getWidth(), backgroundImage.getWidth());
int h = Math.max(baseImage.getHeight(), backgroundImage.getHeight());
BufferedImage combined = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
// paint both images, preserving the alpha channels
Graphics g = combined.getGraphics();
g.drawImage(baseImage, 0, 0, null);
g.drawImage(backgroundImage, 0, 0, null);
int index = baseImg.getFileLocation().lastIndexOf(".png");
String newFileName = baseImg.getFileLocation().substring(0, index);
// Save as new image
ImageIO.write(combined, "PNG", new File(newFileName + "_combined.png"));
but this won't quite work for me because the end result is a 32x32 image with the 2nd image being drawn only.
Any help is appreciated.
Thanks !
It looks like the issue here is you are drawing the 32x32 background image last, meaning it will be printed on top of the other image making it seem as if the 24x24 image was never drawn at all.
If you swap these two lines around, you should see both images. From:
g.drawImage(baseImage, 0, 0, null);
g.drawImage(backgroundImage, 0, 0, null);
to:
g.drawImage(backgroundImage, 0, 0, null);
g.drawImage(baseImage, 0, 0, null);
However this will draw the 24x24 image in the top-left corner, and you said you'd like it in the bottom-right. This can be done with some basic subtraction:
g.drawImage(baseImage, w - baseImage.getWidth(), h - baseImage.getHeight(), null);
Related
I have been following some StackOverflow links using Graphics2D to change the background color of a BufferedImage.
The project I am working on requires that I read in a png image from a given url; the png image retrieved has a transparent background, and I would like to set it to white.
Here is what I have:
String u = this.format() ;
BufferedImage image = null ;
try{
URL url = new URL(u) ;
image = ImageIO.read(url) ;
Graphics2D graphics = image.createGraphics() ;
graphics.setBackground(Color.WHITE) ;
graphics.clearRect(0, 0, image.getWidth(), image.getHeight()) ;
ImageIO.write(image, "png", new File(outPath + fileName)) ;
graphics.dispose() ;
}
catch(IOException e){
e.printStackTrace() ;
}
The problem I am running into is that when I view the image, the image appears as a solid white box. Apparently I have overlaid a white background on top of the existing image that I retrieved.
How can I preserve the original image and only change the background? Or set the background first and then overlay the retrieved image?
1- Load your image
image = ImageIO.read(url) ;
2- Create a new BufferedImage of the same size
BufferedImage background = new BufferedImage(image.getWidth(), image.getHeight, BufferedImage.TYPE_INT_RGB);
3- Fill the background image with the desired color
Graphics2D g2d = background.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, background.getWidth(), background.getHeight());
4- Draw the original image onto the background...
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
background is now filled with the desired color and has the image painted on top o it.
I have a .png image, and I want to extract one part of that image using the PixelReader class, and rebuild it as an image :
Image image = new Image("file:ressources/spritesheets/Zelda_Overworld.png");
byte[] buffer = new byte[1024];
PixelReader pr = image.getPixelReader();
pr.getPixels(0, 0, 16, 16, PixelFormat.getByteBgraInstance(), buffer, 0, 64);
Image tile = new Image(new ByteArrayInputStream(buffer));
I can display image and buffer seems to contain values, but I can't display tile, tile.getPixelReader() returns null, tile.getWidth() and tile.getHeight() return 0.0.
Do you know what I am doing wrong?
Paul
Let WritableImage do this for you:
Image image = new Image("file:ressources/spritesheets/Zelda_Overworld.png");
Image tile = new WritableImage(image.getPixelReader(), x, y, width, height);
Depending on the use of tile doing this may not be necessary at all. ImageView has a viewport property that allows you to choose the part of the image to display and GraphicsContext provides an overloaded version of the drawImage method to draw a part of the image to the Canvas.
Currently, when I load an image off disk,
BufferedImage img = ImageIO.read(new File("myfile.png");
The resulting color space is one of ARGB. What I'd prefer is a plain old RGB, but without having to do the filtering myself.
Is there a way to open an image in a certain color mode?
I'm not aware of a way to open it with a specific color format, but you can create a new BufferedImage of the desired format and draw the old image on to it:
BufferedImage img2 = new BufferedImage(img.getWidth(), img.getHeight(),
BufferedImage.TYPE_INT_RGB);
Graphics2D g = img2.createGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
Any transparent parts in the original image will be drawn over a black background in the new image. If you'd prefer a different background, you can insert these lines before the drawImage call:
g.setColor(Color.white); // or whichever
g.fillRect(0, 0, img.getWidth(), img.getHeight());
It's possible to access the alpha channel of a given bitmap with extractAlpha(), but I haven't been able to find any way to actually set the alpha channel of a bitmap.
How can multiple greyscale images be recombined as channels into a Bitmap with Android?
It is quite possible to re-combine separate channels back into an ARGB image. You just need the grayscale channel images and an image with the alpha channel you want - note that this is not an opaque grayscale image, but an image with the alpha you want. You then draw each channel with a Paint using the appropriate PorterDuffXfermode onto a blank, black-filled Bitmap.
// have your 3 channel grayscales and 1 alpha bitmap loaded by this point
Paint redPaint = new Paint();
redPaint.setXfermode(new PorterDuffXfermode(Mode.LIGHTEN));
redPaint.setShader(new BitmapShader(redChanImg, TileMode.CLAMP, TileMode.CLAMP));
redPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, Mode.DARKEN));
Paint greenPaint = new Paint();
greenPaint.setXfermode(new PorterDuffXfermode(Mode.LIGHTEN));
greenPaint.setShader(new BitmapShader(greenChanImg, TileMode.CLAMP, TileMode.CLAMP));
greenPaint.setColorFilter(new PorterDuffColorFilter(Color.GREEN, Mode.DARKEN));
Paint bluePaint = new Paint();
bluePaint.setXfermode(new PorterDuffXfermode(Mode.LIGHTEN));
bluePaint.setShader(new BitmapShader(blueChanImg, TileMode.CLAMP, TileMode.CLAMP));
bluePaint.setColorFilter(new PorterDuffColorFilter(Color.BLUE, Mode.DARKEN));
Paint alphaPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
alphaPaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
c.setBitmap(resultImage);
c.drawRect(0, 0, width, height, redPaint);
c.drawRect(0, 0, width, height, greenPaint);
c.drawRect(0, 0, width, height, bluePaint);
c.drawBitmap(alphaImg, 0, 0, alphaPaint);
//save off resultImage, display it, etc...
With the above code and the following 4 images (red, green, blue, and alpha, respectively):
We get the following result:
Just a quick note: the red oval is an opaque, red oval on a transparent background - the color doesn't matter for this one, but the alpha does
Manipulating Bitmaps is a farily simple thing, when to access the pixel (bytes) directly.
To do that in Android you can do it over this approch
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
byte[] b = bos.toByteArray();
Now you can do any image manipulation, tranformation or combination you like.
I hope this is what you were looking for.
Have you tried with canvas? The following looks like a hack, but maybe it will work. I have not tested it myself.
Bitmap bitmap;
int color = bitmap.getPixel(1, 123);
Rect rect = new Rect(1,123,2,124);
Canvas c = new Canvas(bitmap);
c.clipRect(rect);
c.drawARGB(50, Color.red(color), Color.green(color), Color.blue(color));
I have two ImageIcons and I want to create a third ImageIcon which has nr 2 drawn upon nr 1.
How would I best do that?
The following code takes an Image from two ImageIcons and creates a new ImageIcon.
The image from the second ImageIcon is drawn on top of the image from the first, then the resulting image is used to make a new ImageIcon:
Image img1 = imageIcon1.getImage();
Image img2 = imageIcon2.getImage();
BufferedImage resultImage = new BufferedImage(
img1.getWidth(null), img1.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = resultImage.createGraphics();
g.drawImage(img1, 0, 0, null);
g.drawImage(img2, 0, 0, null);
g.dispose();
ImageIcon resultImageIcon = new ImageIcon(resultImage);
Edit
(Fixed some errors, added transparency support.)
For allowing transparency, the BufferedImage.TYPE_INT_ARGB can be used for the image type in the constructor, rather than BufferedImage.TYPE_INT_RGB which does not have an alpha channel.