Java padding image - java

I am working on creating an online image editing tool.Looking for some refernce how can I add an image with white space on right side.For example see this image

Presumably, you want to create a new image from an existing image, where the new image has white space on the left and right?
Suppose the unpadded image was a BufferedImage and is called 'image'. Suppose the amount of whitespace you want on each side is 'w'. What you want to do is create a new BufferedImage wider than the original, then paint the entire thing white, and finally draw the smaller image on top of it:
BufferedImage newImage = new BufferedImage(image.getWidth() + 2 * w, image.getHeight(), image.getType());
Graphics g = newImage.getGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, image.getWidth() + 2 * w, image.getHeight());
g.drawImage(image, w, 0, null);
g.dispose();

If anyone comes upon a similar problem, I would definitively recommend imgScalr. You can add padding with literally one line imageSource= Scalr.pad(imageSource,pad,Color.White);.

Create a new BufferedImage object of the right size; use Graphics.fillRect() to paint it white; draw the image into the top-left corner with drawImage(); then save your new image.

Related

Why is my BufferedImage different when drawn to canvas?

Original
https://drive.google.com/file/d/1B3xxfWkGsMs2_MQ_bUQ8_ALYI0DL-LIo/view?usp=sharing
When saved to file
https://drive.google.com/file/d/1z5euXupeHmiFebch4A39fVqGukoUiK0p/view?usp=sharing
When printed to canvas
https://drive.google.com/file/d/1VouD-ygf0pPXFFx9Knr4pv44FHMtoqcV/view?usp=sharing
BufferedImage temp = bImg.getSubimage(100, 100, (int)imgWidth - 100, (int)imgHeight - 100);
try{
ImageIO.write(temp, "png", new File("test.png"));
}catch(Exception e){
e.printStackTrace();
}
gc.drawImage(SwingFXUtils.toFXImage(temp, null), 100, 100);
For some reason if I print an image to the canvas, it is different than if I save the same image to a file. When I save it to a file it correctly calculates the subImage but when I print it to the canvas it disregards the x and y coords I give it and takes a subImage using (0,0) as (x,y) with the given width and height.
From the documentation of the getSubimage method:
Returns a subimage defined by a specified rectangular region. The returned BufferedImage shares the same data array as the original image.
The sub-image is just a “window” into the original image; they are using the same pixel data.
The SwingFXUtils.toFXImage documentation states:
Snapshots the specified BufferedImage and stores a copy of its pixels into a JavaFX Image object, creating a new object if needed.
While it would certainly make sense to only copy the pixels in the source image’s dimensions, the above words don’t make it completely clear that it won’t copy the entire pixel data buffer, thus ignoring the boundaries of a sub-image. I would consider this a bug, but I can see where there might be an argument that it’s not.
In the meantime, you can work around this by extracting a sub-image yourself:
BufferedImage cropped = new BufferedImage(
(int) imgWidth - 100,
(int) imgHeight - 100,
bImg.getType());
Graphics g = cropped.getGraphics();
g.drawImage(bImg, -100, -100, null);
g.dispose();
gc.drawImage(SwingFXUtils.toFXImage(cropped, null), 100, 100);

Can I assign an image gradient to a rectangle

I'm currently making Mario as a school graphics project.
I have most of the collisions done, but I just want the land and bricks to actually look like land and bricks instead of just colored rectangles. I have an ImageIcon for the "land" in my graphics project. The problem is that it is only 16x16 pixels large. In order to make enough land by just making each part of the land one 16x16 pixel, it would essentially be horribly inefficient.
I was wondering if I could get the ImageIcon or possibly buffered image and use it as the "color" for a rectangle to make the chunks of land easier. If that's not possible, can you offer other suggestions on how to go about this problem?
Using a background of tiled images, a texture:
private BufferedImage image;
URL url = getClass().getResource("/mytexture.png");
assert url != null;
image = ImageIO.read(url);
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Rectangle rect = new Rectangle(0, 0, width, height);
Rectangle textureRect = new Rectangle(0, 0, image.getWidth(), image.getHeight());
TexturePaint paint = new TexturePaint(image, textureRect);
g2.setPaint(paint);
g2.fill(rect);
}
In general create your own JPanel.
Gimp and other tools allow to create a tilable image by ensuring that a line running to a border will enter at the opposite border.

Performing setRGB on BufferedImage changes pixel to black instead of color

** Important update, see below! **
I am creating a program that changes the pixels of a BufferedImage to a certain color when that pixel fulfills a set of conditions in Java. However, when I write the image to disk, the pixels that should be colored are instead black.
First I define the color, using RGB codes:
Color purple = new Color(82, 0, 99);
int PURPLE = purple.getRGB();
Then I read the image I want to alter from a File into a BufferedImage called "blank":
BufferedImage blank = ImageIO.read(new File("some path"));
Now, loop through the pixels, and when a pixel at location (x, y) matches a criteria, change its color to purple:
blank.setRGB(x, y, PURPLE);
Now, write "blank" to the disk.
File output = new File("some other path");
ImageIO.write(blankIn, "png", output); // try-catch blocks intentionally left out
The resulting file should be "blank" with some purple pixels, but the pixels in question are instead black. I know for a fact that the issue is with setRGB and NOT any import or export functions, because "blank" itself is a color image, and gets written to file as such. I read around and saw a lot of posts recommending that I use Graphics2D and to avoid setRGB, but with no discussion of pixel-by-pixel color changing.
I also tried direct bit manipulation, like this:
blank.setRGB(x, y, ((82 << 16) + (0 << 8) + 99));
I'm probably doing that wrong, but if I put it in correctly it wouldn't matter, because the pixels are getting set to transparent when I do this (regardless of what the numbers say, which is very strange, to say the least).
** When I try this:
blank.setRGB(x, y, Color.RED.getRGB());
My output file is grayscale, so that means setRGB is, in fact, modifying my picture in grayscale. I think this is actually a rather simple issue, but the solution eludes me.
Based on the insights in https://stackoverflow.com/a/21981173 that you found yourself ... (a few minutes after posting the question) ... it seems that it should be sufficient to simply convert the image into ARGB directly after it was loaded:
public static BufferedImage convertToARGB(BufferedImage image)
{
BufferedImage newImage = new BufferedImage(
image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = newImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}
The original image that was imported into Java was actually grayscale, so when Java read it into the BufferedImage, it simply imported it as a grayscale BufferedImage. By adding a very small but imperceptible colored dot in the corner of my image, I was able to get Java to output a correctly colored image.
Unfortunately, this is only a half solution, because I do not know how to fix this programmatically.
SOLUTION:
Convert the BufferedImage from grayscale to ARGB with this snippet:
BufferedImage blank2 = blank;
// Create temporary copy of blank
blank = new BufferedImage(blank.getWidth(), blank.getHeight(), BufferedImage.TYPE_INT_ARGB);
// Recreate blank as an ARGB BufferedImage
ColorConvertOp convert = new ColorConvertOp(null);
// Now create a ColorConvertOp object
convert.filter(blank2, blank);
// Convert blank2 to the blank color scheme and hold it in blank
You want to add this right after blank = ImageIO.read(new File("some path")).

BufferedImage INT / 4BYTE / USHORT

I know the difference in memory usage between byte, unsigned short, and integer, but when it comes to a BufferedImage, is there a 'speed' difference between them?
I have been using the Image type in my code to store images, but I require an alpha layer. Using BufferedImage provides me with ARGB, but my code is /considerably/ slower after making the change from the Image type (and it was only changed for a few objects), so I'm looking for all the performance improvement I can get.
I'm not sure how stupid of a question this may be, so I thank you in response for any replies.
Tanaki,
I have found that, when in need of using an alpha channel in a BufferedImage, the best is to premultiply the alpha channel. For example:
// Create an ARGB image
BufferedImage bi = new BufferedImage(512, 512, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
// Fill the background (for illustration)
g.setColor(Color.black);
g.fill(new Rectangle(0, 0, 512, 512));
AlphaComposite alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f));
// Keep the original composite
Composite original = g.getComposite();
g.setComposite(alpha);
// Paint with transparency
Rectangle r = new Rectangle(100, 200, 50, 50);
g.setColor(Color.magenta);
g.fillRect(r);
g.setComposite(original);
// ... paint further shapes or images as necessary
// ...
g.dispose();
// Convert to a premultiplied alpha image for fast painting to a Canvas
BufferedImage biPre = new BufferedImage(512, 512, BufferedImage.TYPE_INT_ARGB_PRE);
Graphics2D gPre = biPre.createGraphics();
gPre.drawImage(bi, 0, 0, null);
gPre.dispose();
// clean up:
bi.flush();
// Now use biPre for painting to a Canvas, or a Component.
// ...
// Remember to flush it when done!
biPre.flush();
The reason for painting first to a TYPE_INT_ARGB is to ensure that all alpha gets painted as you expected (not pre-multiplied every time!). Then, when done, paint the whole image onto a TYPE_INT_ARGB_PRE, which is then able to bring the data to the screen with good speed.

java image crop

I am aware of BufferedImage.getSubimage However, it cant deal with cropping images that are smaller than the cropping size throwing the exception:
java.awt.image.RasterFormatException: (y + height) is outside raster
I want to be able to crop either a PNG/JPG/GIF to a certain size however if the image is smaller than the cropping area centre itself on a white background. Is there a call to do this? Or do I need to create an image manually to centre the image on if so, how would I go about this?
Thanks
You cannot crop an image larger, only smaller. So, you start with the goal dimension,let's say 100x100. And your BufferedImage (bi), let's say 150x50.
Create a rectangle of your goal:
Rectangle goal = new Rectangle(100, 100);
Then intersect it with the dimensions of your image:
Rectangle clip = goal.intersection(new Rectangle(bi.getWidth(), bi.getHeight());
Now, clip corresponds to the portion of bi that will fit within your goal. In this case 100 x50.
Now get the subImage using the value of clip.
BufferedImage clippedImg = bi.subImage(clip,1, clip.y, clip.width, clip.height);
Create a new BufferedImage (bi2), the size of goal:
BufferedImage bi2 = new BufferedImage(goal.width, goal.height);
Fill it with white (or whatever bg color you choose):
Graphics2D big2 = bi2.getGraphics();
big2.setColor(Color.white);
big2.fillRect(0, 0, goal.width, goal.height);
and draw the clipped image onto it.
int x = goal.width - (clip.width / 2);
int y = goal.height - (clip.height / 2);
big2.drawImage(x, y, clippedImg, null);

Categories