I'm really confused by this and I can't tell if its a bug or not.
In my SWT app I'm creating a System Tray icon. It shows up just fine, but the transparency is being ignored. The icon is stored as a PNG and viewing it in Preview on OSX shows that the transparency is there, however when it appears on the tray, it has a white background.
The icon is 2 colors, #00000 for background and the alpha is set on that, and then #010101 for the actual icon.
Here is an example of the icon:
Here is how it appears on the bar:
I've had other icons with actual color in them work and have proper transparency, so I can't help but wonder, is this some kind of rendering bug or some oddity with how Mac handles system tray icons?
Update: Channels and layers: http://i.imgur.com/YZNUnXt.png
Update 2:
scratch that
I figured it out, it was a face palm moment, sort of.
All logos were loaded from a loader class I made. There is a method which allows the size of the logo to be specified and then scaled down. I was scaling the logo initially, but after I created the new logo it didn't need to be scaled but I forgot to update that method call.
Here's some code to show what was going on.
public static Image getLogo(LogoType type, Display display, int width, int height) {
ClassLoader loader = AppLogo.class.getClassLoader();
InputStream stream = loader.getResourceAsStream(type.getFileName());
Image img;
if(width > 0 && height > 0) {
Image orig = new Image(display, stream);
img = new Image(display, width, height);
GC gc = new GC(img);
gc.drawImage(orig, 0, 0, orig.getBounds().width, orig.getBounds().height, 0, 0, width, height);
gc.dispose();
orig.dispose();
}
else {
img = new Image(display, stream);
}
return img;
}
It seems that using GC to scale the image causes the alpha values to be ignored. I also tried setting a transparency color on the ImageData but that still doesn't work. I've seen some examples where people use an algorithm to go in and scale and in that case they can actually set the pixels and it works. But drawImage doesn't.
Related
I'm using the approach I found in this answer to create zoom in/out functionality for an image labeling application. However, despite dealing with relatively high resolution images (order of 1500x1500 pixels), the scaling method for zoom leads to pixelation. I checked the image in Windows Photo Viewer and I could definitely zoom in without much pixelation until much more than the 200% zoom I have in my code.
If I resize only compared to the original image (i.e. not cascading each resize call), this works just fine (this is what's in the code snippet). But in order to do this, I lose any drawing functionality. Basically, I would like to be able to do the following:
Load an image
Draw lines/circles/shapes/etc on it
Zoom in (maintaining any drawing on the image)
Draw more
Zoom in/out at will for whatever reasons I need
In summary, the resizing-for-zoom works. It's preserving any additional drawing at each stage of the zoom that I can't seem to get.
Here's a code snippet of my resize function (heavily influenced by that answer cited before):
private void resizeImage()
{
int newImgW = (int)(this.zoom * this.imgW);
int newImgH = (int)(this.zoom * this.imgH);
BufferedImage resized = new BufferedImage(newImgW, newImgH, originalImage.getType());
graphics2D = resized.createGraphics();
graphics2D.drawImage(this.originalImage, 0, 0, newImgW, newImgH, null);
this.image = resized;
repaint();
}
The BufferedImage class implements Transparency, which has three values:
OPAQUE means no transparency.
TRANSLUCENT means every pixel has an Alpha value between 0 and 1.
BITMASK means every pixel is either opaque or completely transparent.
I can check this value with the getTransparency() method. In my case, I have a PNG file with transparency:
pic = ImageIO.read(new File(filename));
int transparency = pic.getTransparency(); // returns Transparency.TRANSLUCENT
Now I read that images with Transparency.BITMASK can be drawn much faster than those with Transparency.TRANSLUCENT and in my case BITMASK would be enough. I would just color all transparent pixels in one specific color and then save the png without transparency.
Question: How to create a BufferedImage object, which has Transparency.BITMASK from an existing BufferedImage by just defining one color as transparent?
You mean something like...
// Create the buffered image
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
BufferedImage bimage = gc.createCompatibleImage(width, height, Transparency.BITMASK);
Things to note:
If you're PNG contains alpha values > 0 and < 255, they are likely to be rounded to either 0 or 1, possibly making the PNG appear jagged...
If you use Transparency.TRANSLUCENT instead, the color mode of the BufferedImage will be compatible with the GraphicsDevice, making it faster to render
I did an animated sequence a few years ago which was made up of 5 separate images, layered on top of each other and played back at separate speeds all on top of a transparent window...When I first tried running it the, the playback was terrible and jumped about the place.
After some playing around, I found that using Transparency.TRANSLUCENT to convert the images to a compatible color model for the GraphicsDevice worked like a charm...
Nothing wrong with the accepted answer, just providing an alternative for completeness (and I think it will work in headless mode). :-)
The transparency of a BufferedImage is controlled by its ColorModel.
So to create a BufferedImage with a given Transparency constant, you can use code like this:
// Use default RGB color space, no discrete alpha channel,
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
ColorModel colorModel = new ComponentColorModel(cs, true, false, Transparency.BITMASK, DataBuffer.TYPE_BYTE);
WritableRaster raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, 4, null);
BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
I'd like to make a splash screen with an animated gif. My animated gif has a transparent background so I'd like to display only the visible part of my gif as a splash screen.
First of all, I must specify that I'm using Matlab so it is not possible (or I haven't found how) to override components/functions.
Here my sample code :
win = javax.swing.JWindow;
jl = javax.swing.JLabel(javax.swing.ImageIcon('C:\Users\ME\Documents\loader512-.gif'));
win.getContentPane.add(jl);
win.setAlwaysOnTop(true);
win.pack;
%% set the splash image to the center of the screen
screenSize = win.getToolkit.getScreenSize;
screenHeight = screenSize.height;
screenWidth = screenSize.width;
% get the actual splashImage size
imgHeight = 512;
imgWidth = 512;
win.setLocation((screenWidth-imgWidth)/2,(screenHeight-imgHeight)/2);
win.show
It works very well shwing the image, however its background is ether white or gray depending on the transparency of the window.
I also tried to play with the background of the JLabel without success.
Please help !
The problem with your code is that every given window has a particular defined shape. Without changing the shape every Window object has a rectangular canvas in which it draws upon. The transparency only applies if you draw a object behind your GIF image. If transparency is enabled the renderer merely draws the background colour (which is normally black or white or some light gray) if nothing else is present.
Since the release of Java 7 a new method called setShape(Shape); appeared for Window objects. If your animated GIF has a fixed transparency "zone" I advise creating a custom java.awt.Shape object in which you pass to the win object via set shape.
Example:
win = javax.swing.JWindow;
jl = javax.swing.JLabel(javax.swing.ImageIcon('C:\Users\ME\Documents\loader512-.gif'));
win.getContentPane.add(jl);
Shape S = createCustomShape(); //Create your shape
win.setShape(S);
win.setAlwaysOnTop(true);
//{rest of code...}
If the animated GIF has a changing transparency background, you must create a complex implementation in which the Shape object updates on a frame by frame basis in response to the GIF. In my opinion, if this is the case, I wouldn't bother. :)
Read more on the Shape object here.
N.B. The Shape "object" is actually a interface, either use one of the implementing subclasses or create your own.
I have an ImageIcon that I used for a button to open this skillsFrame. This size of the image is 100x100px. As you can see in the screenshot if I just put the image it is too large(which is expected).
My question is about how to scale the image to 16x16(or whatever the default size is) so that I don't need to manually create a smaller sized version(for multiple reasons).
In case they make windows bigger in the future
Multiple operating system support
I'm sure I don't need to go on naming more...
skillsFrame = new JInternalFrame("Skills", true, true, false, false);
skillsFrame.setFrameIcon(new ImageIcon("images/gui/button_skills.png"));
And now for the image... the bar at the tops is the buttons to click to open the various JInternalFrames.
how to scale the image to 16x16(or whatever the default size is)
you have look at Image getScaledInstance(int width, int height, int hints)
I am making an application that displays a picture of a room. When the user clicks the picture, an image pops up with the word of the object, and the device says the name. In order to do this, I load a pattern image that has colored blocks in the places of the objects, and a text file that has the different object names mapped to the specific color of the block.
I also made a Java application that can be used to create these two files. The user draws the rectangles over the image, and the application saves the rectangles drawn to a new image file.
Here is the Java code for creating/saving the image:
BufferedImage i = new BufferedImage(img.getWidth(), img.getHeight(),
BufferedImage.TYPE_INT_RGB);
Graphics g = i.getGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, i.getWidth(), i.getHeight());
//draw all the rectangles on the image
for(Rectangle r: rects.keySet()){
g.setColor(rects.get(r));
g.fillRect(r.x, r.y, r.width, r.height);
}
//write the BufferedImage to the file
try {
ImageIO.write(i, "png", saveTo);
} catch (IOException e) {
e.printStackTrace();
}
When I open the picture in Photoshop, Paint, etc, it verifies that the colored blocks are the color they are supposed to be.
When I load them in the Android device, They are not the same color. They differ in a range from 1-3 on each color (so a color that is 25:0:0 is read as 24:0:0 or maybe 22:0:0).
On the device, I load the image as a bitmap, and use a TouchEvent.getX() and getY() to find the position on the image. I then use Bitmap.getPixel(x,y) to get the specific color.
If I use an editor like Photoshop or Paint, I get perfect images that read like normal. My user has asked for their own editor application, so it can create the config file as well.
Sorry for this being so long, and thanks for any help!
Load you colored block as an asset, and not a resource. Android compresses and re-packages bitmaps in the resources folder to minimize their size. I believe the compression is what is causing your colors to shift.
It might be interesting to pull the image from the device using ADB to see if the on-devic e image is actually different. I expect it is.
Bitmaps contained in the assets folder are not processed at all. Use these for images that need to be maintained at their present quality.