I have an image that I would like to shift by some x, y value and then save. My problem is that I would like to keep my original dimensions, so that there is x and y "blank" space left after shifting my image.
Also, is there any way I can set the "blank" space to black?
Example: I shift a 600x600 image down by 45 and left by 30, so that the image is still 600x600 but the result has a 45 height and 30 width of "blank" space.
So far I have been using getSubimage method of BufferedImage to try and solve this but I cannot seem to return to the original dimensions.
Any ideas on how to solve this problem?
You could do that by creating a new buffered image and drawing on to it.
// Create new buffered image
BufferedImage shifted = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// Create the graphics
Graphics2D g = shifted.createGraphics();
// Draw original with shifted coordinates
g.drawImage(original, shiftx, shifty, null);
Hope this works.
public BufferedImage shiftImage(BufferedImage original, int x, int y) {
BufferedImage result = new BufferedImage(original.getWidth() + x,
original.getHeight() + y, original.getType());
Graphics2D g2d = result.createGraphics();
g2d.drawImage(original, x, y, null);
return result;
}
Should work.
Saving
public void SaveImage(BufferedImage image, String filename) {
File outputfile = new File(filename + ".png");
try {
ImageIO.write(image, "png", outputfile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Related
I want to crop an image which is rectangular , into a circle of specific diameter. I am able to do it through graphics2D, and I get the image saved, but, when I read it through ImagIO, i get the full image again inspite to it being cropped to a circle. the image is a masked circle, and evrything outside is discarded like a mask. I am attaching the image here. inspite of it being clipped, i get the full image rendered, when i read it through imageIO. here is the code.
int w = bufferedImage.getWidth();
int h = bufferedImage.getHeight();
BufferedImage output = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = output.createGraphics();
Area areaOval = new Area(new Arc2D.Double(0, 0, w, w, 0, 360,
Arc2D.PIE));
Shape shapeClipSave = g2.getClip();
g2.setClip(areaOval);
g2.drawImage(bufferedImage, 0, 0, null);
g2.setClip(shapeClipSave);
bufferedImage=output;
try {
ImageIO.write(bufferedImage,"png", new File("D:/new.png"));
bufferedImage= ImageIO.read(new File("D:/new.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
g2.dispose();
Here's my take. I rewrote some parts for performance and better fidelity (I couldn't get the edges of the circular area antialiased using clip). Although your code should also work, in general.
public static void main(String[] args) throws IOException {
BufferedImage image = ImageIO.read(new File(args[0]));
// Remove odd borders (imgur issue?)... Remove this if your input doesn't have borders
image = image.getSubimage(10, 0, image.getWidth() - 20, image.getHeight() - 10);
int w = image.getWidth();
int h = image.getHeight();
image = createCircular(image, Math.min(w, h));
if (!ImageIO.write(image, "png", new File("new.png"))) {
System.err.println("Could not write PNG format");
System.exit(1);
}
image = ImageIO.read(new File("new.png"));
showItAll(image);
}
private static BufferedImage createCircular(BufferedImage image, int size) {
BufferedImage output = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = output.createGraphics();
try {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.fillOval(0, 0, size, size);
g2.setComposite(AlphaComposite.SrcIn);
g2.drawImage(image, 0, 0, null);
}
finally {
g2.dispose();
}
return output;
}
private static void showItAll(BufferedImage image) {
JFrame frame = new JFrame("test");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setContentPane(new JPanel() {
{
setBackground(Color.ORANGE);
}
});
frame.getContentPane().add(new JLabel(new ImageIcon(image)));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
Using your giraffe as input, I got the following output, the orange background is just to make the transparent parts clearly visible:
Alternatively, if you use the TwelveMonkeys library and the Adobe Path Support module, you can replace:
image = createCircular(image, Math.min(w, h));
with the following:
int size = Math.min(w, h);
image = Paths.applyClippingPath(new Ellipse2D.Float(0, 0, 1, 1),
image.getSubimage(0, 0, size, size));
Just be aware that the shape coordinates are relative to the size of the image, not in pixels.
I am looking for a way to screenshot my GLCanvas programmatically without awt Robot.
Here is my current setup:
Constructor:
glcaps = new GLCapabilities(GLProfile.get(GLProfile.GL2));
glcaps.setDoubleBuffered(true);
glcaps.setHardwareAccelerated(true);
glcanvas = new GLCanvas(glcaps);
glcanvas.setSize(720, 720);
glcanvas.addGLEventListener(this);
glcanvas is declared as an instance variable: GLCanvas glcanvas
OpenGL init:
#Override
public void init(GLAutoDrawable glad) {
GL2 gl = glad.getGL().getGL2();
glu = new GLU();
gl.glEnable(GL2.GL_DEPTH_TEST);
gl.glDepthFunc(GL2.GL_LEQUAL);
gl.glShadeModel(GL2.GL_SMOOTH);
gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST);
gl.glClearColor(0f, 0f, 0f, 1f);
// Some camera related code not shown
}
OpenGL display:
public void display(GLAutoDrawable glad) {
GL2 gl = glad.getGL().getGL2();
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
...
// Orient camera and draw a simple cube
...
gl.glFlush();
}
Screenshot method:
BufferedImage b = new BufferedImage(glcanvas.getWidth(), glcanvas.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g = b.createGraphics();
glcanvas.setupPrint(glcanvas.getWidth(), glcanvas.getWidth(), 50, 50, 50);
glcanvas.print(g);
try {
ImageIO.write(b, "png", new File("test.png"));
} catch (IOException ex) {
// Error handling
}
glcanvas.releasePrint();
g.dispose();
This method works, as in executes without crashing, but the png file I get is just black with no cube. I also tried using glReadPixels but that does not work either as it just gives me a buffer full of 0's (black).
I think that the problem is that I am not reading glcanvas from the draw thread. Is this the error, and if so, how can I solve it?
All answers appreciated!
First, you have to be sure that you read the framebuffer after what you want to catch has been rendered.
Second, you can do something like this:
protected void saveImage(GL3 gl3, int width, int height) {
try {
BufferedImage screenshot = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics graphics = screenshot.getGraphics();
ByteBuffer buffer = GLBuffers.newDirectByteBuffer(width * height * 4);
// be sure you are reading from the right fbo (here is supposed to be the default one)
// bind the right buffer to read from
gl3.glReadBuffer(GL_BACK);
// if the width is not multiple of 4, set unpackPixel = 1
gl3.glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++) {
// The color are the three consecutive bytes, it's like referencing
// to the next consecutive array elements, so we got red, green, blue..
// red, green, blue, and so on..+ ", "
graphics.setColor(new Color((buffer.get() & 0xff), (buffer.get() & 0xff),
(buffer.get() & 0xff)));
buffer.get(); // consume alpha
graphics.drawRect(w, height - h, 1, 1); // height - h is for flipping the image
}
}
// This is one util of mine, it make sure you clean the direct buffer
BufferUtils.destroyDirectBuffer(buffer);
File outputfile = new File("D:\\Downloads\\texture.png");
ImageIO.write(screenshot, "png", outputfile);
} catch (IOException ex) {
}
}
I filled some comment inside, if something is still unclear, don't hesitate to ask further
How can I remove the white pixels of an image before loading it in the Panel
the method for loading image in panel is:
public void ajouterImage(File fichierImage) {
// desiiner une image à l'ecran
try {
monImage = ImageIO.read(fichierImage);
} catch (IOException e) {
e.printStackTrace();
}
repaint();
}
You can't remove a pixel for say from an image, but you sure can change the color of it, or even make it transparent.
Let's say you have a pixel array as a variable somewhere, and you can give it the RGB value of your BufferedImage. The pixel array will be called pixels:
try {
monImage = ImageIO.read(fichierImage);
int width = monImage.getWidth();
int height = monImage.getHeight();
pixels = new int[width * height];
image.getRGB(0, 0, width, height, pixels, 0, width);
for (int i = 0; i < pixels.length; i++) {
// I used capital F's to indicate that it's the alpha value.
if (pixels[i] == 0xFFffffff) {
// We'll set the alpha value to 0 for to make it fully transparent.
pixels[i] = 0x00ffffff;
}
}
} catch (IOException e) {
e.printStackTrace();
}
Assuming that by removing pixels you mean setting them to transparent, you need to set the alpha value of the image to zero. Here is a function colorToAlpha(BufferedImage, Color) which takes a BufferedImage and a Color as input and returns another BufferedImage with the Color set to transparent.
public static BufferedImage colorToAlpha(BufferedImage raw, Color remove)
{
int WIDTH = raw.getWidth();
int HEIGHT = raw.getHeight();
BufferedImage image = new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_ARGB);
int pixels[]=new int[WIDTH*HEIGHT];
raw.getRGB(0, 0, WIDTH, HEIGHT, pixels, 0, WIDTH);
for(int i=0; i<pixels.length;i++)
{
if (pixels[i] == remove.getRGB())
{
pixels[i] = 0x00ffffff;
}
}
image.setRGB(0, 0, WIDTH, HEIGHT, pixels, 0, WIDTH);
return image;
}
Example usage:
BufferedImage processed = colorToAlpha(rawImage, Color.WHITE)
There is my code. I try to analysis data and create the graph and save to local driver. The program is working fine now. But I find out that the jpg file only can be save to local drive after the program is all finished. However, there are too many data and too many graph need to be created. The whole program may run for hours. I am just wondering could I make it save the jpg in real time? so I can view all graph it just created. Or I don't have to give up all graph if I need to stop the program before it finish all.
Thank you
protected void paintComponent(Graphics g) {
System.out.println("go");
super.paintComponent(g);
BufferedImage jpg = new BufferedImage(1040, 400,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = jpg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = getWidth();
int h = getHeight();
double total=0;
// Draw ordinate.
g2.draw(new Line2D.Double(SPACE, SPACE, SPACE, h-SPACE));
// Draw abcissa.
g2.draw(new Line2D.Double(SPACE, h/2, w-SPACE, h/2));
double xInc = (double)(w - 2*SPACE)/(data.size()-1);
double scale = (double)(h/2 - SPACE*3)/getMax();
// Mark data points.
g2.setPaint(Color.red);
for(int i = 0; i < data.size(); i++) {
double x = SPACE + i*xInc;
double y;
if(data.get(i)!=0){
y= h/2 - SPACE - scale*data.get(i);
total = total + data.get(i);
}else{
y = h/2;
}
g2.fill(new Ellipse2D.Double(x, y-1, 4, 4));
}
try {
ImageIO.write(jpg, "JPEG", new File("111\\"+total/data.size() + ".jpg"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
paintComponent is called as event handling, whenever repainting is needed. And may occur often. Painting should be done fast too. So save the image outside the paint component.
Maybe check the file existence, or number the files.
Call Graphics.dispose() too, to prevent resource leaks.
BufferedImage jpg = new BufferedImage(1040, 400,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = jpg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
paintComponent(g2);
g2.dispose();
Also you picked a program-relative folder. Below I picked the user's folder, and
possibly create a directory 111 if not present (mkdirs).
String userHome = System.getProperty("user.home");
File imgFile = new File(userHome + "/111/" + (total/data.size()) + ".jpg");
// Windows still allows `/` instead of `\` as path separator.
imgFile.getParentFile().mkdirs();
System.out.println("Writing to image: " + imgFile.getPath());
...
ImageIO.write(jpg, "JPEG", imgFile);
I have been working with the polygon class and trying to set the pixel values inside of the polygon to transparent or remove them all together if this is possible, however I have hit a bit of a wall as I am trying to store the values as RGB int values and don't know how I would be able to make a pixel transparent/removed via this method.
Additionally to this I would also like to do the same thing but keeping pixels inside the polygon and deleting those outside if possible in order to be left with only the pixels contained within the polygon. I have searched around for this before but to no avail.
I did attempt to create a SSCCE for this to make it easier to work with and view for anyone taking the time to help however as its part of a much larger programme that I am working on creating one is proving to take some time, however once I have one working to better demonstrate this problem I will edit this post.
Thank you to anyone for taking the time to help me with this problem
Below I have some code for what I am currently using to segment the pixels that are contained within an already specified polygon. This is extremely similar to the way i do it for setting pixels outside the polygon to transparent only with the if statement arguments swapped around to remove a segment of the image and haveing a return for newImage rather than save image stuff and it works perfectly, however when I do it this way to save the pixels contained in the polygon it doesn't save for some reason.
public void saveSegment(int tabNum, BufferedImage img) {
segmentation = new GUI.Segmentation();
Polygon p = new Polygon();
Color pixel;
p = createPolygon(segmentation);
int height = img.getHeight();
int width = img.getWidth();
newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//loop through the image to fill the 2d array up with the segmented pixels
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
//If the pixel is inside polygon
if(p.contains(x, y) == true) {
pixel = new Color(img.getRGB(x, y));
//set pixel equal to the RGB value of the pixel being looked at
int r = pixel.getRed(); // red component 0...255
int g = pixel.getGreen(); // green component 0...255
int b = pixel.getBlue(); // blue component 0...255
int a = pixel.getAlpha(); // alpha (transparency) component 0...255
int col = (a << 24) | (r << 16) | (g << 8) | b;
newImage.setRGB(x, y, col);
}
else {
pixel = new Color(img.getRGB(x, y));
int a = 0; // alpha (transparency) component 0...255
int col = (a << 24);
newImage.setRGB(x, y, col);
}
}
}
try {
//then save as image once all in correct order
ImageIO.write(newImage, "bmp", new File("saved-Segment.bmp"));
JOptionPane.showMessageDialog(null, "New image saved successfully");
} catch (IOException e) {
e.printStackTrace();
}
}
An easier way is to use Java2D's clipping capability:
BufferedImage cutHole(BufferedImage image, Polygon holeShape) {
BufferedImage newImage = new BufferedImage(
image.getWidth(), image.getHeight(), image.getType());
Graphics2D g = newImage.createGraphics();
Rectangle entireImage =
new Rectangle(image.getWidth(), image.getHeight());
Area clip = new Area(entireImage);
clip.subtract(new Area(holeShape));
g.clip(clip);
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}
BufferedImage clipToPolygon(BufferedImage image, Polygon polygon) {
BufferedImage newImage = new BufferedImage(
image.getWidth(), image.getHeight(), image.getType());
Graphics2D g = newImage.createGraphics();
g.clip(polygon);
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}