I have prototyped part of my application in Adobe XD
And now it is time to recreate that frosted glass effect in Java. However, the closest I could get is the following
As the more keen-eyed of you might see...it looks bad, and nothing like my design.
I achieved the look below by taking a screenshot of the relevant part of the screen and applying a gaussian blur to the Image. I have no idea how to achieve the above look so any help would be greatly appreciated.
Below you can see my code thus far
Robot robot = new Robot();
Toolkit myToolkit = Toolkit.getDefaultToolkit();
Dimension screenSize = myToolkit.getScreenSize();
Rectangle screen = new Rectangle(screenSize);
BufferedImage screenBlurImage = robot.createScreenCapture(screen);
//get relevant section
screenBlurImage = screenBlurImage.getSubimage(457,415,1006,107);
//set image
image.setImage(screenBlurImage);
//Apply blur
BoxBlur bb = new BoxBlur();
bb.setWidth(5);
bb.setHeight(5);
bb.setIterations(3);
image.setImage(SwingFXUtils.toFXImage(screenBlurImage, null ));
image.setEffect(bb);
I ended up exporting the Adobe XD Design as an HTML Webpage and rendering it using a JavaFX Webview with transparent background, turns out the way Adobe XD blurs backgrounds is by using the following CSS options:
box-shadow: inset 0 0 0 200px rgba(0, 0, 0, 0.5);
filter: blur(13px);
In a regular Java application, I have a BufferedImage that I would like to manipulate with ImageJ. I have a macro that is exactly what I need to execute. I suspect that the first step is to make an ImagePlus object, but I am not sure how to then run a macro on the ImagePlus object from within Java. Section 7.3 of the ImageJ tutorial found here says:
If you decide to use ImagePlus as your internal image format you can also use all plugins
and macros from the ImageJ distribution as well as all other ImageJ plugins.
But does not indicate how to do so. If someone could explain how, or point me towards a resource that does, I would very much appreciate it.
The following site describes ImageJ API with examples: http://albert.rierol.net/imagej_programming_tutorials.html#ImageJ programming basics
The examples include reading images, processing pixels etc. Well, I guess you will also need to use the API documentation a lot.
Here is a sample code that opens an image, inverts it and saves it back:
import ij.ImagePlus;
import ij.io.FileSaver;
import ij.process.ImageProcessor;
ImagePlus imgPlus = new ImagePlus("path-to-sample.jpg");
ImageProcessor imgProcessor = imgPlus.getProcessor();
imgProcessor.invert();
FileSaver fs = new FileSaver(imgPlus);
fs.saveAsJpeg("path-to-inverted.jpg");
And here's a sample code that shows how to manipulate an image to make it grayscale:
BufferedImage bufferedImage = imgProcessor.getBufferedImage();
for(int y=0;y<bufferedImage.getHeight();y++)
{
for(int x=0;x<bufferedImage.getWidth();x++)
{
Color color = new Color(bufferedImage.getRGB(x, y));
int grayLevel = (color.getRed() + color.getGreen() + color.getBlue()) / 3;
int r = grayLevel;
int g = grayLevel;
int b = grayLevel;
int rgb = (r<<16) | (g<<8) | b;
bufferedImage.setRGB(x, y, rgb);
}
}
ImagePlus grayImg = new ImagePlus("gray", bufferedImage);
fs = new FileSaver(grayImg);
fs.saveAsJpeg("path-to-gray.jpg");
I hope it helps you get started :)
Here is an opensource project implementation with imagej for photo sharing web app.
Use this as a reference to implement imagej apis in your application
http://www.gingercart.com/Home/java-snippets/create-image-thumbnail-in-java-using-imagej-api
Here is the original image: http://rank.my/public/images/uploaded/orig-4193395691714613396.png
And here it is scaled down to 300x225:
http://rank.my/public/images/uploaded/norm-4193395691714613396.png
And here it is scaled down to 150x112:
http://rank.my/public/images/uploaded/small-4193395691714613396.png
As you can see, 300x225 looks pretty bad, and 150x112 looks awful. Here is the code I'm using to scale down the image:
private static BufferedImage createResizedCopy(final BufferedImage source, final int destWidth,
final int destHeight) {
final BufferedImage resized = new BufferedImage(destWidth, destHeight, source.getType());
final Graphics2D bg = resized.createGraphics();
bg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
bg.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
bg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
final float sx = (float) destWidth / source.getWidth();
final float sy = (float) destHeight / source.getHeight();
bg.scale(sx, sy);
bg.drawImage(source, 0, 0, null);
bg.dispose();
return resized;
}
What am I doing wrong here? The image scaling doesn't have to be especially fast, quality is definitely a priority over speed. Am I using the wrong technique?
There are three ways to fix the downscaling problem. First is to do it in multiple steps, with no more than a 75% reduction in each step. The second is to blur the image before resizing; the more it shrinks, the more you'll have to blur. The third way is to use a method that filters using more than the 2x2 to 4x4 pixel blocks used by a naive bilinear or bicubic interpolation method. As the shrink factor grows larger, so should the pixel block used by the filter, otherwise you get aliasing artifacts as you've seen here.
I've never used these libraries so I feel unqualified to answer, but I can't help but pass along these links I found that I think may be useful. Hopefully this will help.
http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html
http://www.componenthouse.com/article-20
JAI is pretty frustrating. I still wonder why, no matter what settings you do, it never matches the speed, quality and simplicity of ImageMagick. I prefer to use ImageMagick wherever I can.
The code below is what gives me best result for image scaling. Please note that I have used RenderingHints.VALUE_RENDER_QUALITY and SubsampleAverage and not RenderingHints.VALUE_INTERPOLATION_BICUBIC.
I have wrapped up JAI processing in a small block and always use it to scale down. The same code does not give good result when you scale-up -- a different setting applies for that. I have not tried with PNG, JPEG is what I worked with.
Hope this helps
//Set-up and load file
PlanarImage image = JAI.create("fileload", absPath);
RenderingHints quality = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
Properties p = new Properties(System.getProperties());
p.put("com.sun.media.jai.disableMediaLib", "true");
System.setProperties(p);
//Setup the processes
ParameterBlock pb = new ParameterBlock()
.addSource(image)
.add(scaleX) //scaleX = (double)1.0*finalX/origX
.add(scaleY); //scaleY = (double)1.0*finalY/origY
RenderedOp tempProcessingFile = JAI.create("SubsampleAverage", pb, quality);
//Save the file
FileOutputStream fout = new FileOutputStream(file);
JPEGEncodeParam encodeParam = new JPEGEncodeParam();
encodeParam.setQuality(0.92f); //My experience is anything below 0.92f gives bad result
ImageEncoder encoder = ImageCodec.createImageEncoder("JPEG", fout, encodeParam);
encoder.encode(tempProcessingFile.getAsBufferedImage());
Also, the articles that helped me are.
https://jaistuff.dev.java.net/docs/jaitutorial.pdf
http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html
http://forums.sun.com/thread.jspa?threadID=5332078 Looks like after Oracle acquisition they have washed away the forum posts. This was an extra-ordinary discussion over JAI performance and quality. I still had it bookmarked.
http://www.digitalsanctuary.com/tech-blog/java/how-to-resize-uploaded-images-using-java-better-way.html
(The links above are from my bookmark, edit them if you find they are dead)
I need to resize PNG, JPEG and GIF files. How can I do this using Java?
FWIW I just released (Apache 2, hosted on GitHub) a simple image-scaling library for Java called imgscalr (available on Maven central).
The library implements a few different approaches to image-scaling (including Chris Campbell's incremental approach with a few minor enhancements) and will either pick the most optimal approach for you if you ask it to, or give you the fastest or best looking (if you ask for that).
Usage is dead-simple, just a bunch of static methods. The simplest use-case is:
BufferedImage scaledImage = Scalr.resize(myImage, 200);
All operations maintain the image's original proportions, so in this case you are asking imgscalr to resize your image within a bounds of 200 pixels wide and 200 pixels tall and by default it will automatically select the best-looking and fastest approach for that since it wasn't specified.
I realize on the outset this looks like self-promotion (it is), but I spent my fair share of time googling this exact same subject and kept coming up with different results/approaches/thoughts/suggestions and decided to sit down and write a simple implementation that would address that 80-85% use-cases where you have an image and probably want a thumbnail for it -- either as fast as possible or as good-looking as possible (for those that have tried, you'll notice doing a Graphics.drawImage even with BICUBIC interpolation to a small enough image, it still looks like garbage).
After loading the image you can try:
BufferedImage createResizedCopy(Image originalImage,
int scaledWidth, int scaledHeight,
boolean preserveAlpha)
{
System.out.println("resizing...");
int imageType = preserveAlpha ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, imageType);
Graphics2D g = scaledBI.createGraphics();
if (preserveAlpha) {
g.setComposite(AlphaComposite.Src);
}
g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
g.dispose();
return scaledBI;
}
Thumbnailator is an open-source image resizing library for Java with a fluent interface, distributed under the MIT license.
I wrote this library because making high-quality thumbnails in Java can be surprisingly difficult, and the resulting code could be pretty messy. With Thumbnailator, it's possible to express fairly complicated tasks using a simple fluent API.
A simple example
For a simple example, taking a image and resizing it to 100 x 100 (preserving the aspect ratio of the original image), and saving it to an file can achieved in a single statement:
Thumbnails.of("path/to/image")
.size(100, 100)
.toFile("path/to/thumbnail");
An advanced example
Performing complex resizing tasks is simplified with Thumbnailator's fluent interface.
Let's suppose we want to do the following:
take the images in a directory and,
resize them to 100 x 100, with the aspect ratio of the original image,
save them all to JPEGs with quality settings of 0.85,
where the file names are taken from the original with thumbnail. appended to the beginning
Translated to Thumbnailator, we'd be able to perform the above with the following:
Thumbnails.of(new File("path/to/directory").listFiles())
.size(100, 100)
.outputFormat("JPEG")
.outputQuality(0.85)
.toFiles(Rename.PREFIX_DOT_THUMBNAIL);
A note about image quality and speed
This library also uses the progressive bilinear scaling method highlighted in Filthy Rich Clients by Chet Haase and Romain Guy in order to generate high-quality thumbnails while ensuring acceptable runtime performance.
You don't need a library to do this. You can do it with Java itself.
Chris Campbell has an excellent and detailed write-up on scaling images - see this article.
Chet Haase and Romain Guy also have a detailed and very informative write-up of image scaling in their book, Filthy Rich Clients.
Java Advanced Imaging is now open source, and provides the operations you need.
If you are dealing with large images or want a nice looking result it's not a trivial task in java. Simply doing it via a rescale op via Graphics2D will not create a high quality thumbnail. You can do it using JAI, but it requires more work than you would imagine to get something that looks good and JAI has a nasty habit of blowing our your JVM with OutOfMemory errors.
I suggest using ImageMagick as an external executable if you can get away with it. Its simple to use and it does the job right so that you don't have to.
If, having imagemagick installed on your maschine is an option, I recommend im4java. It is a very thin abstraction layer upon the command line interface, but does its job very well.
The Java API does not provide a standard scaling feature for images and downgrading image quality.
Because of this I tried to use cvResize from JavaCV but it seems to cause problems.
I found a good library for image scaling: simply add the dependency for "java-image-scaling" in your pom.xml.
<dependency>
<groupId>com.mortennobel</groupId>
<artifactId>java-image-scaling</artifactId>
<version>0.8.6</version>
</dependency>
In the maven repository you will get the recent version for this.
Ex. In your java program
ResampleOp resamOp = new ResampleOp(50, 40);
BufferedImage modifiedImage = resamOp.filter(originalBufferedImage, null);
You could try to use GraphicsMagick Image Processing System with im4java as a comand-line interface for Java.
There are a lot of advantages of GraphicsMagick, but one for all:
GM is used to process billions of
files at the world's largest photo
sites (e.g. Flickr and Etsy).
Image Magick has been mentioned. There is a JNI front end project called JMagick. It's not a particularly stable project (and Image Magick itself has been known to change a lot and even break compatibility). That said, we've had good experience using JMagick and a compatible version of Image Magick in a production environment to perform scaling at a high throughput, low latency rate. Speed was substantially better then with an all Java graphics library that we previously tried.
http://www.jmagick.org/index.html
Simply use Burkhard's answer but add this line after creating the graphics:
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
You could also set the value to BICUBIC, it will produce a better quality image but is a more expensive operation. There are other rendering hints you can set but I have found that interpolation produces the most notable effect.
Keep in mind if you want to zoom in in a lot, java code most likely will be very slow. I find larger images start to produce lag around 300% zoom even with all rendering hints set to optimize for speed over quality.
You can use Marvin (pure Java image processing framework) for this kind of operation:
http://marvinproject.sourceforge.net
Scale plug-in:
http://marvinproject.sourceforge.net/en/plugins/scale.html
It turns out that writing a performant scaler is not trivial. I did it once for an open source project: ImageScaler.
In principle 'java.awt.Image#getScaledInstance(int, int, int)' would do the job as well, but there is a nasty bug with this - refer to my link for details.
I have developed a solution with the freely available classes ( AnimatedGifEncoder, GifDecoder, and LWZEncoder) available for handling GIF Animation.
You can download the jgifcode jar and run the GifImageUtil class.
Link: http://www.jgifcode.com
you can use following popular product: thumbnailator
If you dont want to import imgScalr like #Riyad Kalla answer above which i tested too works fine, you can do this
taken from Peter Walser answer #Peter Walser on another issue though:
/**
* utility method to get an icon from the resources of this class
* #param name the name of the icon
* #return the icon, or null if the icon wasn't found.
*/
public Icon getIcon(String name) {
Icon icon = null;
URL url = null;
ImageIcon imgicon = null;
BufferedImage scaledImage = null;
try {
url = getClass().getResource(name);
icon = new ImageIcon(url);
if (icon == null) {
System.out.println("Couldn't find " + url);
}
BufferedImage bi = new BufferedImage(
icon.getIconWidth(),
icon.getIconHeight(),
BufferedImage.TYPE_INT_RGB);
Graphics g = bi.createGraphics();
// paint the Icon to the BufferedImage.
icon.paintIcon(null, g, 0,0);
g.dispose();
bi = resizeImage(bi,30,30);
scaledImage = bi;// or replace with this line Scalr.resize(bi, 30,30);
imgicon = new ImageIcon(scaledImage);
} catch (Exception e) {
System.out.println("Couldn't find " + getClass().getName() + "/" + name);
e.printStackTrace();
}
return imgicon;
}
public static BufferedImage resizeImage (BufferedImage image, int areaWidth, int areaHeight) {
float scaleX = (float) areaWidth / image.getWidth();
float scaleY = (float) areaHeight / image.getHeight();
float scale = Math.min(scaleX, scaleY);
int w = Math.round(image.getWidth() * scale);
int h = Math.round(image.getHeight() * scale);
int type = image.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
boolean scaleDown = scale < 1;
if (scaleDown) {
// multi-pass bilinear div 2
int currentW = image.getWidth();
int currentH = image.getHeight();
BufferedImage resized = image;
while (currentW > w || currentH > h) {
currentW = Math.max(w, currentW / 2);
currentH = Math.max(h, currentH / 2);
BufferedImage temp = new BufferedImage(currentW, currentH, type);
Graphics2D g2 = temp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(resized, 0, 0, currentW, currentH, null);
g2.dispose();
resized = temp;
}
return resized;
} else {
Object hint = scale > 2 ? RenderingHints.VALUE_INTERPOLATION_BICUBIC : RenderingHints.VALUE_INTERPOLATION_BILINEAR;
BufferedImage resized = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = resized.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(image, 0, 0, w, h, null);
g2.dispose();
return resized;
}
}
Try this folowing method :
ImageIcon icon = new ImageIcon("image.png");
Image img = icon.getImage();
Image newImg = img.getScaledInstance(350, 350, java.evt.Image.SCALE_SMOOTH);
icon = new ImageIcon(img);
JOptionPane.showMessageDialog(null, "image on The frame", "Display Image", JOptionPane.INFORMATION_MESSAGE, icon);
you can also use
Process p = Runtime.getRuntime().exec("convert " + origPath + " -resize 75% -quality 70 " + largePath + "");
p.waitFor();
Design jLabel first:
JLabel label1 = new JLabel("");
label1.setHorizontalAlignment(SwingConstants.CENTER);
label1.setBounds(628, 28, 169, 125);
frame1.getContentPane().add(label1); //frame1 = "Jframe name"
Then you can code below code(add your own height and width):
ImageIcon imageIcon1 = new ImageIcon(new ImageIcon("add location url").getImage().getScaledInstance(100, 100, Image.SCALE_DEFAULT)); //100, 100 add your own size
label1.setIcon(imageIcon1);
My application allows the user to print the screen content which is made of several Swing controls (images, texts, etc.) - the printed panel it self is long (several pages) and the width about 600pixels.
Since I know exactly each page layout (I put the exact number of images and components) on each page (the total number of images is dynamic), I can calculate exactly how many pages I will need for the print.
I've implemented the Printable interface as follows:
public int print(Graphics g, PageFormat pf, int pageIndex) throws PrinterException {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLACK); //set default foreground color to black
RepaintManager.currentManager(this).setDoubleBufferingEnabled(false);
Dimension d = this.getSize(); //get size of document
double panelWidth = d.width; //width in pixels
double panelHeight = d.height; //height in pixels
double pageHeight = pf.getImageableHeight(); //height of printer page
double pageWidth = pf.getImageableWidth(); //width of printer page
double scale = pageHeight / panelHeight;
int totalNumPages = (int) Math.ceil(scale * panelWidth / pageWidth);
if (pageIndex >= totalNumPages) {
return Printable.NO_SUCH_PAGE;
}
g2.translate(pf.getImageableX(), pf.getImageableY());
g2.translate(0f, -pageIndex * pageHeight);
g2.scale(scale, scale);
this.paint(g2);
return Printable.PAGE_EXISTS;
}
It seems that everything works fine.
Since I don't have a printer, I've tested it using a PDF printer and on several clients printer - and the results were good.
However, on one of my user's printer - it seems that something in not working with the calculation, since it breaks the page in the middle of the images.
Is there a more elegant way to do these calculations ?
Can I add instead a "page break" notification somewhere ?
Thanks
In the past I have found that trying to implement the printable interface myself has caused formatting issues such as you are experiencing. One thing I have done in the past that greatly reduced the effort on my part, and worked well, was using JasperReports to manage this. You could create a jrxml definition that has one image/page, and then just pass the images into the jasperreport. From here you can use the JasperPrint object and send this directly to the printer. This has worked well for me. In addition it has several benefits with the exports already build in to jasper reports such as pdf if needed.
The code itself looks ok, especially considering it works for the PDF printer. I just have some ideas for debugging:
1) Have you checked the printer settings for the user's printer? Maybe the page size is not set correctly.
2) Any way you could hook up your development machine to that printer and debug it?
3) If not, you could add logging to tell you the pg.getImageableWidth and pg.getImageableHeight and other information throughout the calculation to see where it's wrong.