Okay. So I'm trying to rotate the cursor image or the cursor itself depending on it's position. I have tried using
Graphics2D g2d = (Graphics2D)g;
AffineTransform old = g2d.getTransform();
g2d.rotate(Math.toRadians(degrees));
Toolkit toolkit = Toolkit.getDefaultToolkit(); //Get the default toolkit
Image image = toolkit.getImage("pictures/skills/skill" +InfoReader.SkillData("CastImage") +".png"); //Load an image for the cursor
Cursor cursor = toolkit.createCustomCursor(image, new Point(0, 0), "Cursor");
setCursor(cursor);
g2d.setTransform(old);
So I was thinking that this should rotate the image, but g2d.rotate() doesen't seem to have any effect on cursor? I'm not 100% sure if it has affect on the image itself. Atleast the cursor image is what I want it to be though.
EDIT: Here's an example video :) (In my case, I just want to rotate it around a certain point which stays on the same spot all the time). https://www.youtube.com/watch?v=TQ71QXa-B-s
While searching and asking around for the solution of a similar problem I've found your question and also the answer to it. This is the code I use in my program and it works. Note that this method was designed to be called only once and calling it constantly might require optimization. Also I've learned AffineTransform today and might have made some mistakes(even though code works).
Basically I rotate an image, create a new image from it and set the new image as the cursor.
My "cursor.png" is in the data folder.
private void rotateCursor(double rotation) {
// Get the default toolkit
Toolkit toolkit = Toolkit.getDefaultToolkit();
// Load an image for the cursor
BufferedImage image = null;
try {
image = ImageIO.read(this.getClass().getResource("/data/cursor.png"));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
AffineTransform at = new AffineTransform();
// affineTransform applies the added transformations in the reverse order
// 3. translate it back to the center of the picture
at.translate(image.getWidth() / 2, image.getWidth() / 2);
at.rotate(rotation);//2- adds rotation to at (they are not degrees)
//1- translate the object so that you rotate it around the center
at.translate(-image.getWidth() / 2, -image.getHeight() / 2);
BufferedImage rotated = null; // creates new image that will be the transformed image
// makes this: at + image= rotated
AffineTransformOp affineTransformOp = new AffineTransformOp(at,
AffineTransformOp.TYPE_BILINEAR);
image2 = affineTransformOp.filter(image, rotated);
// Create the hotSpot for the cursor
Point hotSpot = new Point(10, 0); // click position of the cursor(ex: + shape's is middle)
Cursor cursor = toolkit.createCustomCursor(rotated, hotSpot, "cursor");
// Use the custom cursor
this.setCursor(cursor);
}
You can use window.getMousePosition().x; and window.getMousePosition().y; for getting mouse position if you are using a mouseListener.
You need to call rotateCursor() method with the correct double. How to calculate the correct double is something I can't help you with.
I hope it helps.
I've learned these from these sources:
storing transformed BufferedImage in Java
http://www.codebeach.com/2008/02/using-custom-cursors-in-java.html
Rotating BufferedImage instances
http://stumpygames.wordpress.com/2012/07/22/particles-tutorial-foundation/ (this tutorial also has a mouse listener)
It seems a bit confusing to me, what are you trying to rotate?
Lets imagine you have a BufferedImage object, you may get a Graphics2D object from it, and by operationg over it, you may get what you want.
java.awt.image.BufferedImage buffImage = null;
try {
java.io.InputStream imageStream =
MyClass.class.getResourceAsStream( "pictures/skills/skill" +InfoReader.SkillData("CastImage") +".png" );
//MyClass is anyclass that you use as relative path...
//use ClassLoader.getSystemClassLoader().getResourceAsStream( ... )
//for a absolute path
buffImage = javax.imageio.ImageIO.read( imageStream );
}
catch ( java.io.IOException | IllegalArgumentException ex ) {
//It may throw IllegalArgumentException if imageStream is null.
}
Graphics2D g2d = buffImage.createGraphics();
try {
AffineTransform old = g2d.getTransform();
g2d.rotate(Math.toRadians(degrees));
g2d.setTransform(old);
}finally {
g2d.dispose();
}
Toolkit toolkit = Toolkit.getDefaultToolkit(); //Get the default toolkit
Cursor cursor = toolkit.createCustomCursor(image, new Point(0, 0), "Cursor");
setCursor(cursor);
Now, if you intend to rotate it while you use it, I'm not sure how, but I hope I have helped a bit.
EDIT: Try to see this link, it might help you: https://www.google.com/#q=java+rotate+Cursor
EDIT 2: I see now what you want exaclty, I don't know how to help you, but try to see the link I gave you (yes it is from google). Even if you don't find much, it might help you in your quest.
Related
I was looking at this question and I was looking at the first answer.
So I tried to use this code:
public static Image getIcon(String fileName) throws Exception {
File file = new File(fileName);
FileSystemView view = FileSystemView.getFileSystemView();
Icon icon = view.getSystemIcon(file);
ImageIcon imageIcon = (ImageIcon) icon;
Image image = imageIcon.getImage();
return image;
}
Which does return an Image (or throws an Error) but the Image has terribly low resolution.
I am assuming that this is because the 16x16 Image is returned.
Is there any way to state which Image I want to be returned?
Java offers you two possibilities to retrieve file icons.
You already know the first one:
Icon icon = FileSystemView.getFileSystemView().getSystemIcon(new File(FILENAME));
that gives you a 16x16 pixel result.
The other one using ShellFolder
Icon icon = new ImageIcon(ShellFolder.getShellFolder(new File(FILENAME)).getIcon(true));
will retrieve you the larger one (32x32) depending on the boolean flag getLargeIcon in the getIcon method.
I'm sorry for you but more is (at the moment) not possible with the java default libraries. Interest exists as you can read in this JDK bugreport.
But nothing has been done so far.
If you really want to have larger versions you will need to retrieve them with the OS depending native calls or store them manually as local application ressources.
Note: If you have problems accessing ShellFolder you should read this question.
I used this method:
protected ImageIcon getImageIcon() {
File f = new File((iconPath!=null)?iconPath:"");
if (!f.isFile() || !f.canRead()) {
iconPath = Constants.getDefaultPreviewIconPath();
}
ImageIcon icon = new ImageIcon(iconPath, titolo);
return new ImageIcon(Utils.getScaledImage(
icon.getImage(),
Constants.getICON_WIDTH(),
Constants.getICON_HEIGTH()));
}
where getScaledImage is:
public static Image getScaledImage(Image srcImg, int w, int h) {
BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = resizedImg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(srcImg, 0, 0, w, h, null);
g2.dispose();
return resizedImg;
}
I want to give a visual indication that a node has been transferred to clipboard with a "Cut" action. One intuitive look used by at least one proprietary OS is to make this the same image, but slightly transparent.
I'd quite like to know whether it is in fact possible somehow to use the icons used by the Windoze OS (W7)... but I'd be more intrigued if it were possible to interfere in some way (in the renderer) with the Icon, by somehow messing with the Graphics object used by Icon.paintIcon() ... just for a given node, obviously. I'm not clear where an Icon goes hunting for the Graphics object it uses when it is painted ... any enlightenment would be most welcome.
later
Many thanks to MadProgrammer. Spotted this possibility as a way of extracting obfuscated visuals with a view to their manipulation: https://home.java.net/node/674913 ... it works. Putting code here in case of broken link...
public class IconTest {
public static void main(String[] args) {
Icon leafIcon = UIManager.getIcon("Tree.leafIcon");
// ... ("Tree.closedIcon") ("Tree.openIcon")
BufferedImage img1 = new BufferedImage(leafIcon.getIconWidth(),
leafIcon.getIconHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g = img1.createGraphics();
g.drawImage(((ImageIcon) leafIcon).getImage(), 0, 0, null);
g.dispose();
try {
ImageIO.write(img1, "PNG", new File("leafIcon.png"));
} catch (IOException e) {
System.out.println("Error writing to file leafIcon" + ", e = " + e);
System.exit(0);
}
}
}
Then use MadProgrammer's technique to alter the image in any way one likes: change transparency, colour, etc. Great stuff.
I'd quite like to know whether it is in fact possible somehow to use the icons used by the Windoze OS (W7)
FileSystemView#getSystemIcon will give you the OS's icon representation of a given File, for example...
Icon icon = FileSystemView.getFileSystemView().getSystemIcon(new File("ThatImportantDoc.docx"));
I want to give a visual indication that a node has been transferred to clipboard with a "Cut" action. One intuitive look used by at least one proprietary OS is to make this the same image, but slightly transparent.
You need to paint the previous Icon to BufferedImage, which has had a AlphaComposite applied to it, for example
BufferedImage img = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
icon.paintIcon(null, g2d, 0, 0);
g2d.dispose();
You then need to wrap the resulting BufferedImage in a ImageIcon, which allows you to pass the image as a Icon to the rest of the API.
JPanel panel = new JPanel();
panel.add(new JLabel(icon));
panel.add(new JLabel(new ImageIcon(img)));
JOptionPane.showMessageDialog(null, panel, "Icon", JOptionPane.PLAIN_MESSAGE);
To get this to finally work, you will need to provide a TreeCellRenderer capable of supporting your functionality. Have a look at How to Use Trees for more details
Just one tweak enabling me to do what I mainly wanted to do: get the UI images "from the source code".
public class IconTest {
public static void main(String[] args) {
// OS folder icon
// Icon icon = FileSystemView.getFileSystemView().getSystemIcon(new File("."));
// proprietary word processor
// Icon icon = FileSystemView.getFileSystemView().getSystemIcon(new File("Doc1.docx"));
// taken from PNG file
// Icon icon = new ImageIcon( "openIcon.png" );
// taken directly from the Java images held somewhere (?) in the code
Icon icon = UIManager.getIcon("Tree.leafIcon");
// Icon icon = UIManager.getIcon("Tree.openIcon");
// ... ("Tree.closedIcon") ("Tree.openIcon")
BufferedImage img = new BufferedImage( icon.getIconWidth(),
icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setComposite(AlphaComposite.SrcOver.derive( 0.5f));
icon.paintIcon(null, g2d, 0, 0);
g2d.dispose();
JPanel panel = new JPanel();
panel.add(new JLabel(icon));
panel.add(new JLabel(new ImageIcon(img)));
JOptionPane.showMessageDialog(null, panel, "Icon", JOptionPane.PLAIN_MESSAGE);
}
}
I know this is something to do with compositing but I can't work out what. In an earlier section of code, a particular list of pixels in a BufferedImage are set to be transparent black:
for(Pixel p : closed){
Color c = new Color(image.getRGB(p.x, p.y));
Color newC = new Color(0,0,0, 0);
image.setRGB(p.x, p.y, newC.getRGB() & 0x00000000);
}
if(andCrop){
image = image.getSubimage(left, top, right-left, bottom-top);
}
return image;
Then I attempt to write the image out:
try {
BufferedImage out = new BufferedImage(image.getWidth(), image.getHeight(), java.awt.Transparency.TRANSLUCENT);
Graphics2D g2d = out.createGraphics();
g2d.setComposite(AlphaComposite.Clear);
g2d.fillRect(0, 0, image.getWidth(), image.getHeight());
g2d.setComposite(AlphaComposite.Src);
g2d.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
g2d.dispose();
File outputfile = new File(file);
ImageIO.write(out, "png", outputfile);
} catch (IOException e) {
}
Now, I know that 'out' is clear before I attempt to draw the image onto it. What I'm not getting is what's wrong with my compositing. Instead of coming out as transparent, I'm getting full-black.
All bufferedimages used are INT_ARGB.
EDIT - This has been solved. The image source was from ImageIO.read and the BufferedImage returned did not support alpha. A quick post-read conversion let the rest of the code run smoothly.
Things that comes to my mind... (thanks to Andrew):
java.awt.Transparency.TRANSLUCENT = 3
TYPE_INT_ARGB = 2
TYPE_INT_ARGB_PRE = 3
public BufferedImage(int width,
int height,
int imageType)
Constructs a BufferedImage of one of the predefined image types. (TYPE_...)
http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/image/BufferedImage.html
so it seems as basically it's a mixup.
Besides, what is the effect you want to achieve? you clear an empty image, then draw fully transparent pixels to it... I just don't get it.
Whelp, this has been downvoted now so I'm not sure this will be relevant, but the issue was that the original BufferedImage was being read in by ImageIO, and this image was not supporting ARGB. A quick post-read conversion allowed the rest of the code to work.
I am trying to implement a simple class that will allow a user to crop an image to be used for their profile picture. This is a java web application.
I have done some searching and found that java.awt has a BufferedImage class, and this appears (at first glance) to be perfect for what I need. However, it seems that there is a bug in this (or perhaps java, as I have seen suggested) that means that the cropping does not always work correctly.
Here is the code I am using to try to crop my image:
BufferedImage profileImage = getProfileImage(form, modelMap);
if (profileImage != null) {
BufferedImage croppedImage = profileImage
.getSubimage(form.getStartX(), form.getStartY(), form.getWidth(), form.getHeight());
System.err.println(form.getStartX());
System.err.println(form.getStartY());
File finalProfileImage = new File(form.getProfileImage());
try {
String imageType = getImageType(form.getProfileImage());
ImageIO.write(croppedImage, imageType, finalProfileImage);
}
catch (Exception e) {
logger.error("Unable to write cropped image", e);
}
}
return modelAndView;
}
protected BufferedImage getProfileImage(CropImageForm form, Map<String, Object> modelMap) {
String profileImageFileName = form.getProfileImage();
if (validImage(profileImageFileName) && imageExists(profileImageFileName)) {
BufferedImage image = null;
try {
image = getCroppableImage(form, ImageIO.read(new File(profileImageFileName)), modelMap);
}
catch (IOException e) {
logger.error("Unable to crop image, could not read profile image: [" + profileImageFileName + "]");
modelMap.put("errorMessage", "Unable to crop image. Please try again");
return null;
}
return image;
}
modelMap.put("errorMessage", "Unable to crop image. Please try again.");
return null;
}
private boolean imageExists(String profileImageFileName) {
return new File(profileImageFileName).exists();
}
private BufferedImage getCroppableImage(CropImageForm form, BufferedImage image, Map<String, Object> modelMap) {
int cropHeight = form.getHeight();
int cropWidth = form.getWidth();
if (cropHeight <= image.getHeight() && cropWidth <= image.getWidth()) {
return image;
}
modelMap.put("errorMessage", "Unable to crop image. Crop size larger than image.");
return null;
}
private boolean validImage(String profileImageFileName) {
String extension = getImageType(profileImageFileName);
return (extension.equals("jpg") || extension.equals("gif") || extension.equals("png"));
}
private String getImageType(String profileImageFileName) {
int indexOfSeparator = profileImageFileName.lastIndexOf(".");
return profileImageFileName.substring(indexOfSeparator + 1);
}
The form referred to in this code snippet is a simple POJO which contains integer values of the upper left corner to start cropping (startX and startY) and the width and height to make the new image.
What I end up with, however, is a cropped image that always starts at 0,0 rather than the startX and startY position. I have inspected the code to make sure the proper values are being passed in to the getSubimage method, and they appear to be.
Are there simple alternatives to using BufferedImage for cropping an image. I have taken a brief look at JAI. I would rather add a jar to my application than update the jdk installed on all of the production boxes, as well as any development/testing servers and local workstations.
My criteria for selecting an alternative are:
1) simple to use to crop an image as this is all I will be using it for
2) if not built into java or spring, the jar should be small and easily deployable in a web-app
Any suggestions?
Note: The comment above that there is an issue with bufferedImage or Java was something I saw in this posting: Guidance on the BufferedImage.getSubimage(int x, int y, int w, int h) method?
I have used getSubimage() numerous times before without any problems. Have you added a System.out.println(form.getStartX() + " " + form.getStartY()) before that call to make sure they're not both 0?
Also, are you at least getting an image that is form.getWidth() x form.getHeight()?
Do make sure you are not modifying/disposing profileImage in any way since the returned BufferedImage shares the same data array as the parent.
The best way is to just simply draw it across if you want a completely new and independent BufferedImage:
BufferedImage croppedImage = new BufferedImage(form.getWidth(),form.getHeight(),BufferedImage.TYPE_INT_ARGB);
Graphics g = croppedImage.getGraphics();
g.drawImage(profileImage,0,0,form.getWidth(),form.getHeight(),form.getStartX(),form.getStartY(),form.getWidth(),form.getHeight(),null);
g.dispose();
You can do it in this manner as well (code is not 100% tested as I adopted for example from an existing app i did):
import javax.imageio.*;
import java.awt.image.*;
import java.awt.geom.*;
...
BufferedImage img = ImageIO.read(imageStream);
...
/*
* w = image width, h = image height, l = crop left, t = crop top
*/
ColorModel dstCM = img.getColorModel();
BufferedImage dst = new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(w, h), dstCM.isAlphaPremultiplied(), null);
Graphics2D g = dst.createGraphics();
g.drawRenderedImage(img, AffineTransform.getTranslateInstance(-l,-t));
g.dispose();
java.io.File outputfile = new java.io.File(sessionScope.get('absolutePath') + java.io.File.separator + sessionScope.get('lastUpload'));
ImageIO.write(dst, 'png', outputfile);
Thanks for all who replied. It turns out that the problem was not in the cropping code at all.
When I displayed the image to be cropped, I resized it to fit into my layout nicely, then used a javascript cropping tool to figure out the coordinates to crop.
Since I had resized my image, but didn't take the resizing into account when I was determining the cropping coordinates, I ended up with coordinates that appeared to coincide with the top left corner.
I have changed the display to no longer resize the image, and now cropping is working beautifully.
I'd like to convert gif images to jpeg using Java. It works great for most images, but I have a simple transparent gif image:
Input gif image http://img292.imageshack.us/img292/2103/indexedtestal7.gif
[In case the image is missing: it's a blue circle with transparent pixels around it]
When I convert this image using the following code:
File file = new File("indexed_test.gif");
BufferedImage image = ImageIO.read(file);
File f = new File("indexed_test.jpg");
ImageIO.write(image, "jpg", f);
This code works without throwing an Exception, but results an invalid jpeg image:
[In case the image is missing: IE cannot show the jpeg, Firefox shows the image with invalid colors.]
I'm using Java 1.5.
I also tried converting the sample gif to png with gimp and using the png as an input for the Java code. The result is the same.
Is it a bug in the JDK? How can I convert images correctly preferably without 3rd party libraries?
UPDATE:
Answers indicate that jpeg conversion cannot handle transparency correctly (I still think that this is a bug) and suggest a workaround for replacing transparent pixels with predefined color. Both of the suggested methods are quite complex, so I've implemented a simpler one (will post as an answer). I accept the first published answer with this workaround (by Markus). I don't know which implementation is the better. I go for the simplest one still I found a gif where it's not working.
For Java 6 (and 5 too, I think):
BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
g = bufferedImage.createGraphics();
//Color.WHITE estes the background to white. You can use any other color
g.drawImage(image, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), Color.WHITE, null);
As already mentioned in the UPDATE of the question I've implemented a simpler way of replacing transparent pixels with predefined color:
public static BufferedImage fillTransparentPixels( BufferedImage image,
Color fillColor ) {
int w = image.getWidth();
int h = image.getHeight();
BufferedImage image2 = new BufferedImage(w, h,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = image2.createGraphics();
g.setColor(fillColor);
g.fillRect(0,0,w,h);
g.drawRenderedImage(image, null);
g.dispose();
return image2;
}
and I call this method before jpeg conversion in this way:
if( inputImage.getColorModel().getTransparency() != Transparency.OPAQUE) {
inputImage = fillTransparentPixels(inputImage, Color.WHITE);
}
The problem (at least with png to jpg conversion) is that the color scheme isn't the same, because jpg doesn't support transparency.
What we've done successfully is something along these lines (this is pulled from various bits of code - so please forgive the crudeness of the formatting):
File file = new File("indexed_test.gif");
BufferedImage image = ImageIO.read(file);
int width = image.getWidth();
int height = image.getHeight();
BufferedImage jpgImage;
//you can probably do this without the headless check if you just use the first block
if (GraphicsEnvironment.isHeadless()) {
if (image.getType() == BufferedImage.TYPE_CUSTOM) {
//coerce it to TYPE_INT_ARGB and cross fingers -- PNGs give a TYPE_CUSTOM and that doesn't work with
//trying to create a new BufferedImage
jpgImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
} else {
jpgImage = new BufferedImage(width, height, image.getType());
}
} else {
jgpImage = GraphicsEnvironment.getLocalGraphicsEnvironment().
getDefaultScreenDevice().getDefaultConfiguration().
createCompatibleImage(width, height, image.getTransparency());
}
//copy the original to the new image
Graphics2D g2 = null;
try {
g2 = jpg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2.drawImage(image, 0, 0, width, height, null);
}
finally {
if (g2 != null) {
g2.dispose();
}
}
File f = new File("indexed_test.jpg");
ImageIO.write(jpgImage, "jpg", f);
This works for png to jpg and gif to jpg. And you will have a white background where the transparent bits were. You can change this by having g2 fill the image with another color before the drawImage call.
3 months late, but I am having a very similar problem (although not even loading a gif, but simply generating a transparent image - say, no background, a colored shape - where when saving to jpeg, all colors are messed up, not only the background)
Found this bit of code in this rather old thread of the java2d-interest list, thought I'd share, because after a quick test, it is much more performant than your solution:
final WritableRaster raster = img.getRaster();
final WritableRaster newRaster = raster.createWritableChild(0, 0, img.getWidth(), img.getHeight(), 0, 0, new int[]{0, 1, 2});
// create a ColorModel that represents the one of the ARGB except the alpha channel
final DirectColorModel cm = (DirectColorModel) img.getColorModel();
final DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(), cm.getRedMask(), cm.getGreenMask(), cm.getBlueMask());
// now create the new buffer that we'll use to write the image
return new BufferedImage(newCM, newRaster, false, null);
Unfortunately, I can't say I understand exactly what it does ;)
If you create a BufferedImage of type BufferedImage.TYPE_INT_ARGB and save to JPEG weird things will result. In my case the colors are scewed into orange. In other cases the produced image might be invalid and other readers will refuse loading it.
But if you create an image of type BufferedImage.TYPE_INT_RGB then saving it to JPEG works fine.
I think this is therefore a bug in Java JPEG image writer - it should write only what it can without transparency (like what .NET GDI+ does). Or in the worst case thrown an exception with a meaningful message e.g. "cannot write an image that has transparency".
JPEG has no support for transparency. So even when you get the circle color correctly you will still have a black or white background, depending on your encoder and/or renderer.
BufferedImage originalImage = ImageIO.read(getContent());
BufferedImage newImage = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
for (int x = 0; x < originalImage.getWidth(); x++) {
for (int y = 0; y < originalImage.getHeight(); y++) {
newImage.setRGB(x, y, originalImage.getRGB(x, y));
}
}
ImageIO.write(newImage, "jpg", f);
7/9/2020 Edit: added imageIO.write