I want to remove a strip (widthways) of an image by moving the top part of the image to the bottom. Currently I'm doing this but I think that maybe there is a more efficiently way to achieve this without creating a new BufferedImage.
Snippet code:
BufferedImage myImage = ...;
...
BufferedImage imgPart_1 = myImage.getSubimage(0, 0, myImage.getWidth(), (myImage.getHeight()/2)-50);
BufferedImage imgPart_2 = myImage.getSubimage(0, myImage.getHeight()/2, myImage.getWidth(), myImage.getHeight()/2);
BufferedImage newImage = new BufferedImage(myImage.getWidth(), myImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = newImage.createGraphics();
g.drawImage(imgPart_1, 0, 0, null);
g.drawImage(imgPart_2, 0, imgPart_1.getHeight(), null);
myImage = newImage;
...
Thanks in advance.
You will have to create a new Image, but you don't have to paint it yourself.
You can use the CropImageFilter to get your image.
Toolkit toolkit = Toolkit.getDefaultToolkit();
CropImageFilter cropFilter = new CropImageFilter
(x, y, imageWidth, imageHeight);
Image croppedImage = toolkit.createImage(new FilteredImageSource
(image.getSource(), cropFilter));
Looks pretty efficient to me: are you really sure there is a performance problem here?
If you really want to avoid creating a new bufferedimage, you can use myImage as the destination, i.e. just do:
Graphics g = myImage.createGraphics();
g.drawImage(imgPart_1, 0, 0, null);
g.drawImage(imgPart_2, 0, imgPart_1.getHeight(), null);
I think this will work OK in your case, although you will need to test (there can be some odd effects when the source and destination areas are overlapping!)
Related
How to blur a portion of an image, to hide some privates parts like credit card informations.
I try to use ConvolveOp.class like :
float[] matrix = new float[400];
for (int i = 0; i < 400; i++)
matrix[i] = 1.0f/500.0f;
BufferedImage sourceImage = (BufferedImage) image; ;
BufferedImage destImage = null ;
BufferedImageOp op = new ConvolveOp( new Kernel(20, 20, matrix), ConvolveOp.EDGE_NO_OP, null );
BufferedImage blurredImage = op.filter(sourceImage, destImage);
it seems to work, except that the image is completely blurred.
In the case you want to focus on the application and not on the specifics of image processing, you can use an image processing framework like Marvin. Thus, you can do more with less code.
Input image:
Output image:
Source code:
import static marvin.MarvinPluginCollection.*;
public class PortionBlur {
public PortionBlur(){
// 1. Load image
MarvinImage image = MarvinImageIO.loadImage("./res/credit_card.jpg");
// 2. Create masks for each blurred region
MarvinImageMask mask1 = new MarvinImageMask(image.getWidth(), image.getHeight(), 38,170,345,24);
MarvinImageMask mask2 = new MarvinImageMask(image.getWidth(), image.getHeight(), 52,212,65,24);
MarvinImageMask mask3 = new MarvinImageMask(image.getWidth(), image.getHeight(), 196,212,65,20);
MarvinImageMask mask4 = new MarvinImageMask(image.getWidth(), image.getHeight(), 38,240,200,20);
// 3. Process Image with each mask
GaussianBlur gaussianBlur = new GaussianBlur();
gaussianBlur.load();
gaussianBlur.attributes.set("radius",15);
gaussianBlur.process(image.clone(), image, mask1);
gaussianBlur.process(image.clone(), image, mask2);
gaussianBlur.process(image.clone(), image, mask3);
gaussianBlur.process(image.clone(), image, mask4);
// 4. Save the final image
MarvinImageIO.saveImage(image, "./res/credit_card_out.jpg");
}
public static void main(String[] args) {
new PortionBlur();
System.exit(0);
}
}
Gaussian blur algorithm source code:
https://github.com/gabrielarchanjo/marvinproject/blob/master/marvinproject/dev/MarvinPlugins/src/org/marvinproject/image/blur/gaussianBlur/GaussianBlur.java
I don't know whether this can be done by changing the matrix values, but this should definitely be possible by filtering a subimage, since, according to the BufferedImage.getSubimage() documentation:
The returned BufferedImage shares the same data array as the original image.
So the original BufferedImage should change with code like this:
BufferedImage image = /* ... */;
BufferedImage subImage = image.getSubimage(10, 20, 30, 40); // x, y, width, height
new ConvolveOp(new Kernel(20, 20, matrix), ConvolveOp.EDGE_NO_OP, null).filter(subImage, subImage);
I didn't test this though, and I can imagine that filter doesn't work as expected if source and destination are the same, in which case you could use a copy of the subimage, using the solution from this question:
BufferedImage image = /* ... */;
BufferedImage dest = image.getSubimage(10, 20, 30, 40); // x, y, width, height
ColorModel cm = dest.getColorModel();
BufferedImage src = new BufferedImage(cm, dest.copyData(dest.getRaster().createCompatibleWritableRaster()), cm.isAlphaPremultiplied(), null).getSubimage(0, 0, dest.getWidth(), dest.getHeight());
new ConvolveOp(new Kernel(20, 20, matrix), ConvolveOp.EDGE_NO_OP, null).filter(src, dest);
After that, continue working with image (not subImage, src or dest!)
Currently, when I load an image off disk,
BufferedImage img = ImageIO.read(new File("myfile.png");
The resulting color space is one of ARGB. What I'd prefer is a plain old RGB, but without having to do the filtering myself.
Is there a way to open an image in a certain color mode?
I'm not aware of a way to open it with a specific color format, but you can create a new BufferedImage of the desired format and draw the old image on to it:
BufferedImage img2 = new BufferedImage(img.getWidth(), img.getHeight(),
BufferedImage.TYPE_INT_RGB);
Graphics2D g = img2.createGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
Any transparent parts in the original image will be drawn over a black background in the new image. If you'd prefer a different background, you can insert these lines before the drawImage call:
g.setColor(Color.white); // or whichever
g.fillRect(0, 0, img.getWidth(), img.getHeight());
I am currently scaling images using the following code.
Image scaledImage = img.getScaledInstance( width, int height, Image.SCALE_SMOOTH);
BufferedImage imageBuff = new BufferedImage(width, scaledImage.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics g = imageBuff.createGraphics();
g.drawImage(scaledImage, 0, 0, new Color(0, 0, 0), null);
g.dispose();
ImageIO.write(imageBuff, "jpg", newFile);
Anyone have an idea of a better way of scaling an image and getting better quality results, or even any help on improving my current code to get better quality output.
You can use Affine Transorm
public static BufferedImage getScaledImage(BufferedImage image, int width, int height) throws IOException {
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
double scaleX = (double)width/imageWidth;
double scaleY = (double)height/imageHeight;
AffineTransform scaleTransform = AffineTransform.getScaleInstance(scaleX, scaleY);
AffineTransformOp bilinearScaleOp = new AffineTransformOp(scaleTransform, AffineTransformOp.TYPE_BILINEAR);
return bilinearScaleOp.filter(
image,
new BufferedImage(width, height, image.getType()));
}
Also try this Example .
Also Try java-image-scaling library
You might want to look at this image scaling library. It has algorithms like bicubic and Lanczos and also an unsharp filter.
Try avoiding Image.getScaledInstance().
I'm trying to draw 2 images, one on top of the other. The 1'st image is an arrow (that should appear like a header in the final image). The 1'st image (arrow) is 32x32 px while the 2'nd is 24x24.
Ideally I would like to draw the 2'nd image on top of the 1'st, starting from the right-bottom corner of the 1'st image.
Currently I'm using such code
// load source images
BufferedImage baseImage = ImageIO.read(new File(baseImg.getFileLocation()));
BufferedImage backgroundImage = ImageIO.read(new File(backgroundImg.getFileLocation()));
// create the new image, canvas size is the max. of both image sizes
int w = Math.max(baseImage.getWidth(), backgroundImage.getWidth());
int h = Math.max(baseImage.getHeight(), backgroundImage.getHeight());
BufferedImage combined = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
// paint both images, preserving the alpha channels
Graphics g = combined.getGraphics();
g.drawImage(baseImage, 0, 0, null);
g.drawImage(backgroundImage, 0, 0, null);
int index = baseImg.getFileLocation().lastIndexOf(".png");
String newFileName = baseImg.getFileLocation().substring(0, index);
// Save as new image
ImageIO.write(combined, "PNG", new File(newFileName + "_combined.png"));
but this won't quite work for me because the end result is a 32x32 image with the 2nd image being drawn only.
Any help is appreciated.
Thanks !
It looks like the issue here is you are drawing the 32x32 background image last, meaning it will be printed on top of the other image making it seem as if the 24x24 image was never drawn at all.
If you swap these two lines around, you should see both images. From:
g.drawImage(baseImage, 0, 0, null);
g.drawImage(backgroundImage, 0, 0, null);
to:
g.drawImage(backgroundImage, 0, 0, null);
g.drawImage(baseImage, 0, 0, null);
However this will draw the 24x24 image in the top-left corner, and you said you'd like it in the bottom-right. This can be done with some basic subtraction:
g.drawImage(baseImage, w - baseImage.getWidth(), h - baseImage.getHeight(), null);
I'm using a RenderedImage to display tiffs in a DisplayJAI in my app.
Somebody know how to resize an instance of RenderedImage??
It's been a long time since I've done anything with JAI, but wouldn't the "Scale" or "Affine" operations suffice?
Edit: Here are a couple of links into the Programmer's Guide for "Scale" and "Affine".
public static RenderedImage scale(RenderedImage image, float scaleFactor)
RenderingHints hints = new RenderingHints(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
RenderedOp resizeOp = SubsampleAverageDescriptor.create(image,
Double.valueOf(scaleFactor), Double.valueOf(scaleFactor), hints);
BufferedImage bufferedResizedImage = resizeOp.getAsBufferedImage();
return bufferedResizedImage;
}
There is an example code posted here to just that:
http://answers.yahoo.com/question/index?qid=20090827075608AA12kEZ
Relevant code:
BufferedImage img = ImageIO.read(new File("~/your/file/system/example.jpeg"));
BufferedImage thumb = new BufferedImage(w2, h2, BufferedImage.TYPE_INT_RGB);
thumb.createGraphics().drawImage(
img.getScaledInstance(w2, h2, java.awt.Image.SCALE_SMOOTH), 0, 0, null);
File file = new File(fullpath + filename);
ImageIO.write(thumb, "png", file);