I've setup a method for loading an image into a ByteBuffer and called Display.setIcon(), this works... partially. This sets the icon of the taskbar, but leaves the window's icon as the default LWJGL icon. Is there another Display method I need to call? Or is this something to do with windows.
Here's the method of loading the icon if needed:
public static final ByteBuffer[] getIcon()
{
Image image = Toolkit.getDefaultToolkit().getImage("rw_icon.PNG");
MediaTracker tracker = new MediaTracker(new JPanel());
tracker.addImage(image, 0);
try
{
tracker.waitForAll();
}
catch(InterruptedException e)
{
e.printStackTrace();
}
tracker.removeImage(image);
BufferedImage bufImage = new BufferedImage(32, 32, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D graphics = bufImage.createGraphics();
graphics.drawImage(image, 0, 0, null);
graphics.dispose();
image.flush();
ByteBuffer buffer = ByteBuffer.allocateDirect(32*32*4);
buffer.clear();
byte[] bufferData = (byte[])bufImage.getRaster().getDataElements(0, 0, 32, 32, null);
buffer.put(bufferData);
buffer.rewind();
return (new ByteBuffer[] {buffer});
}
No.
You just need to pass an array of two versions of the icon (16x16, 32x32) to the setIcon(..) method.
It seems like you misunderstood the ByteBuffer[]. You are supposed to pass an array of different ByteBuffers. Not just a ByteBuffer array with one element in it. Therefore it would probably be best to create a new method which basically just does what your getIcon() method does, but expects a String as a file path. That way you can easily create the real array of icon byte-buffers.
public static int setIcon(java.nio.ByteBuffer[] icons)
Sets one or more icons for the Display. On Windows you should supply at least one
16x16 icon and one 32x32. Linux (and similar platforms) expect one
32x32 icon. Mac OS X should be supplied one 128x128 icon The
implementation will use the supplied ByteBuffers with image data in
RGBA (size must be a power of two) and perform any conversions
nescesarry for the specific platform.
NOTE: The display will make a
deep copy of the supplied byte buffer array, for the purpose of
recreating the icons when you go back and forth fullscreen mode. You
therefore only need to set the icon once per instance.
http://lwjgl.org/javadoc/org/lwjgl/opengl/Display.html#setIcon(java.nio.ByteBuffer[])
Related
I'm working on an application which allows a used to place controls, move, resize, etc. But I'm trying to add icon images to a button control. When placed and instanced, it resizes the icon image per the code below.
But when I resize the control using user features and it calls this routing again, it fails to resize the image and it remains the original icon size. I've tried using "this.", passing the control to itself, I've done prints to ensure it's seeing the new size and width... what I am missing?
Also, when I create a 2nd control (or 3rd, etc), it uses the 1st image's initial size.
Thanks!
protected void sizeIcon () {
try {
File f2 = new File("media\\button.gif");
BufferedImage inputImage = ImageIO.read(f2);
BufferedImage img = new BufferedImage(this.getWidth(), this.getHeight(), inputImage.getType());
Graphics2D g = img.createGraphics();
g.drawImage(inputImage, 7, 0, this.getWidth(), this.getHeight(), null);
ImageIO.write(img, "gif", new File("test.gif"));
this.setIcon(new ImageIcon("test.gif"));
g.dispose();
} catch(Exception e) {System.out.println(e);}
Sorry, got it, appears the old file was not being replaces.
-MH
I would like to extract a rectangle of a BufferedImage.
Javadoc propose getSubImage(x,y,w,h) and getData(rectangle).
getData is cool but I don't want only the raster. I want the subimage as a BufferedImage object but I also need a modified version of it data array but the javadoc says
public BufferedImage getSubimage(int x,int y,int w,int h) : Returns a subimage defined by a specified rectangular region. The returned BufferedImage shares the same data array as the original image.
Q: how can I extract a subimage with a shrinked data array ?
Given a BufferedImage image, here's 3 ways to create a "deep" copy subimage:
// Create an image
BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_4BYTE_ABGR);
// Fill with static
new Random().nextBytes(((DataBufferByte) image.getRaster().getDataBuffer()).getData());
Create an image around the already deep copy of the Raster you get from getData(rect). This involves casting to WritableRaster, so it may break with some Java implementations or in the future. Should be quite fast, as you only copy the data once:
// Get sub-raster, cast to writable and translate it to 0,0
WritableRaster data = ((WritableRaster) image.getData(new Rectangle(25, 25, 50, 50))).createWritableTranslatedChild(0, 0);
// Create new image with data
BufferedImage subOne = new BufferedImage(image.getColorModel(), data, image.isAlphaPremultiplied(), null);
Another option, creating a sub image the "normal way", then copying the raster into a new image. Involves creating one sub-raster, still copies only once (and no casting):
// Get subimage "normal way"
BufferedImage subimage = image.getSubimage(25, 25, 50, 50);
// Create empty compatible image
BufferedImage subTwo = new BufferedImage(image.getColorModel(), image.getRaster().createCompatibleWritableRaster(50, 50), image.isAlphaPremultiplied(), null);
// Copy data into the new, empty image
subimage.copyData(subTwo.getRaster());
Finally, the easier route, just painting the subimage over a new empty image. Could be slightly slower, as it involves the rendering pipeline, but I think it should perform reasonably still.
// Get subimage "normal way"
BufferedImage subimage = image.getSubimage(25, 25, 50, 50);
// Create new empty image of same type
BufferedImage subThree = new BufferedImage(50, 50, image.getType());
// Draw the subimage onto the new, empty copy
Graphics2D g = subThree.createGraphics();
try {
g.drawImage(subimage, 0, 0, null);
}
finally {
g.dispose();
}
I had the same issue a long time ago, I didn't want a shared raster. The only solution I found was to create a BufferedImage that represents the sub-image, and then copy the pixels into the sub-image.
In order to have something really fast, I access directly the DataBuffer and I make array copies (line by line) using System.arraycopy()
So I have an assignment where I need to create a catalog.
The catalog needs to have a list, an image and a description.
My entire code works, so I have no issue with the coding as such.
I do have an issue with the image size.
How do I take care of images on a java gui program to make them all into one size when it is running.
Please let me know :D
When you read in an image, create a new BufferedImage that is the exact size that you desire, get it's Graphics object via getGraphics(), draw the original image into the new image using Graphics#drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) where x and y are 0 and width and height are from the dimensions of the new image, dispose() of the Graphics object, and then display the new Image as an ImageIcon in a JLabel. Make sure though that the original image is the same size or larger than the new one, else your images will look gawd-awful.
For example, and note that this code may not be exactly correct since I don't have my IDE up:
BufferedImage originalImage = ImageIO.read(something); // read in original image
// create new empty image of desired size
BufferedImage newImage = new BufferedImage(desiredWidth, desiredHeight, BufferedImage.TYPE_INT_ARGB);
Graphics g = newImage.getGraphics(); // get its graphics object
// draw old image into new image
g.drawImage(originalImage, 0, 0, desiredWidth, desiredHeight, null);
g.dispose(); // get rid of Graphics object
// create ImageIcon and put in JLabel to display
Icon newIcon = new ImageIcon(newImage);
myJLabel.setIcon(newIcon);
I would propably create a JPanel to draw on one Image, and then work with the method:
myPanel.setSize(new Dimension(x,y))
or
myPanel.setPreferredSize(new Dimension....)
There is a method (image = imgobj.getScaledInstance(width, height, hints)) in awt.Image class which provides re-sizing capabilities very nicely, I always use this to re-size my images when I need. Please see here some examples :-), I hope it will work for you, it is the most convenient way to scale images I have ever seen. create a method pass the image to the method and size of the image you want and return the image back in return to reuse the code ;)
This question already has an answer here:
Load large picture from file and add watermark
(1 answer)
Closed 8 years ago.
I have a large jpeg file say 10000 x 150000 px. I want to add a small logo to the bottom of the image without re sizing.
I am able to do this If i down sample the original image and draw the logo using canvas.But when i finally save it to file, the image original size will be reduced as I am sampling it.
If i load the original image into bitmap without down sampling, it exceeds the VM.
Below code work for me :-
public static Bitmap mark(Bitmap src, String watermark, Point location, Color color, int alpha, int size, boolean underline) {
int w = src.getWidth();
int h = src.getHeight();
Bitmap result = Bitmap.createBitmap(w, h, src.getConfig());
Canvas canvas = new Canvas(result);
canvas.drawBitmap(src, 0, 0, null);
Paint paint = new Paint();
paint.setColor(color);
paint.setAlpha(alpha);
paint.setTextSize(size);
paint.setAntiAlias(true);
paint.setUnderlineText(underline);
canvas.drawText(watermark, location.x, location.y, paint);
return result;
}
For large image editing you'll need to use native tools like imagemagick. Because there seem to be a lack of advanced image processing libraries in android supported Java.
If you can compile Composite tool's binaries for android. Then you can use them with --limit option to work with limited memory.
Also, you can try OpenCV as an alternative.
You can use BitmapRegionDecoder when deal with large image file. From the official document.
BitmapRegionDecoder can be used to decode a rectangle region from an image. BitmapRegionDecoder is particularly useful when an original image is large and you only need parts of the image.
To create a BitmapRegionDecoder, call newInstance(...). Given a BitmapRegionDecoder, users can call decodeRegion() repeatedly to get a decoded Bitmap of the specified region.
Just decode the part of your image that you need to add watermark, then use Canva to draw text on it.
try {
BitmapRegionDecoder regionDecoder = BitmapRegionDecoder.newInstance("/sdcard/test.png", true);
Bitmap bitmap = regionDecoder.decodeRegion(rect, options);
} catch (IOException e) {
e.printStackTrace();
}
This is a question, wether I am using the right way or not. And by the right way, I mean, is there a more memory-efficient way to do this?
I use 1 image source:
String imgurl = "imgreadertest8.png";
BufferedImage loadedimage = ImageIO.read(getClass().getResource(imgurl));
BufferedImage image = ImageIO.read(getClass().getResource(imgurl));
I draw the image in a paint() method. But sometimes I need to set the brightness:
public void setBrightness(float brightness)
{
RescaleOp rescaleOp = new RescaleOp(brightness, 15, null);
rescaleOp.filter(loadedimage, image);
}
So I read the same image, two times. One to have a 'final' BufferedImage (it's not really final... But I cannot use final in this context, because it needs to be used outside the constructor (which you can't see here, but it is)) which is used as template, and one to edit and draw.
More information: Before trying this way, I did this:
String imgurl = "imgreadertest8.png";
BufferedImage loadedimage = ImageIO.read(getClass().getResource(imgurl));
BufferedImage image = loadedimage;
But when I edit the image, it edits the loadedimage as well. Pretty much because they're the same object.
So... Is there another way to set the brightness of this image, WITHOUT loading the same image two times?
The following would copy an image.
public static BufferedImage copy(BufferedImage img) {
Hashtable<?,?> properties = new Hashtable<>();
for (String propertyName : img.getPropertyNames()) {
properties.put(propertyName, img.getProperty(propertyName));
}
return new BufferedImage(img.getColorModel(),
img.copyData(null),
img.isAlphaPremultiplied(), properties);
}
The same thing can be achieved slower but simplier by creating an empty image, drawing in the createGraphics of it (not to forget dispose). If you need a Graphics2D to process the image, that might be an option too.