Java ,Image Resize, Blur / Convert Formats JPG, PNG, GIF

I have a requirement where in i have to scale all input images to a given size dynamically. I have been searching over web to do this and found really hard time to settle on a simple solution. Here is the simple solution without need of any Library

To read this image, we can use the ImageIO class:

BufferedImage image = ImageIO.read(new File("c:\picture.jpg"));
First Attempt
Now we have to find a way to resize this image. Our first attempt is to use the drawImage() method of the Graphics interface:

private static BufferedImage resize(BufferedImage image, int width, int height) {
BufferedImage resizedImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(image, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
With this method, we can create a 24×24 avatar by calling:

Image resized = resize(image, 24, 24);
The last step is to save the image so that we can see the results. The ImageIO class can do this job:

ImageIO.write(resized, “png”, new File(“c:\picture1.png”));
Note that the second parameter is the format of the saved image. I used “png” because it is simpler. If you want to save it as JPG, you will have to use the JPEGImageEncoder class (and the result is the same, trust me).

The result of this method is a low-quality image:

Second Attempt
We noticed that the main problem of the resize() method above is the fact that it doesn’t have anti-aliasing. So we could use the Rendering Hints of the Java2D API as an attempt to solve that problem:

private static BufferedImage resize(BufferedImage image, int width, int height) {
int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
BufferedImage resizedImage = new BufferedImage(width, height, type);
Graphics2D g = resizedImage.createGraphics();
g.setComposite(AlphaComposite.Src);

g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);

g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);

g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);

g.drawImage(image, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}

The Trick
Now I will explain how to improve the quality of this image. Basically, the trick is to blur the image before resizing. The code that blurs an image in java is:

public static BufferedImage blurImage(BufferedImage image) {
float ninth = 1.0f/9.0f;
float[] blurKernel = {
ninth, ninth, ninth,
ninth, ninth, ninth,
ninth, ninth, ninth
};

Map map = new HashMap();

map.put(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);

map.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

map.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

RenderingHints hints = new RenderingHints(map);
BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, blurKernel), ConvolveOp.EDGE_NO_OP, hints);
return op.filter(image, null);
}

Since the original image is in the JPG format, we can’t blur it directly. We have to create a compatible image first:

private static BufferedImage createCompatibleImage(BufferedImage image) {
GraphicsConfiguration gc = BufferedImageGraphicsConfig.getConfig(image);
int w = image.getWidth();
int h = image.getHeight();
BufferedImage result = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
Graphics2D g2 = result.createGraphics();
g2.drawRenderedImage(image, null);
g2.dispose();
return result;
}
Blurring the image before resizing it isn’t the only trick. You have to do this when the width or height of the image is 100px. Since small avatars are usually a square (width = height), you can resize it to 100×100, call the blur() method and resize again to 24×24:

private static BufferedImage resizeTrick(BufferedImage image, int width, int height) {
image = createCompatibleImage(image);
image = resize(image, 100, 100);
image = blurImage(image);
image = resize(image, width, height);
return image;
}

(the resize() method is the one described in the second attempt)

Here is final Code

/**
*
*/
package com.linkwithweb.image;

import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;

import sun.awt.image.BufferedImageGraphicsConfig;

/**
* High-Quality Image Resize with Java
*
* Following two articles are source for this program
*
* http://www.componenthouse.com/article-20
* http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html
*
* @author ashwink
*/
public class ImageResizer{

public static void main(String[] args) {
try {
/*
* BufferedImage image = ImageIO
* .read(new File(
* “C:\\setup\\Apache\\Apache2.2\\htdocs\\northalley\\Registration_files\\menu_logo.png”));
*/

BufferedImage image = ImageIO
.read(new File(
“C:\\Documents and Settings\\kumara\\Desktop\\SiriFinalDocs\\SiriWork\\SWScan0000200008.jpg”));

ImageIO.write(
resizeTrick(image, image.getWidth(), image.getHeight()),
“png”,
new File(
“C:\\setup\\Apache\\Apache2.2\\htdocs\\northalley\\Registration_files\\test.png”));
} catch (IOException e) {
e.printStackTrace();
}
}

private static BufferedImage resize(BufferedImage image, int width,
int height) {
int type = image.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : image
.getType();
BufferedImage resizedImage = new BufferedImage(width, height, type);
Graphics2D g = resizedImage.createGraphics();
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(image, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}

private static BufferedImage resizeTrick(BufferedImage image, int width,
int height) {
image = createCompatibleImage(image);
image = resize(image, width, height);

/**
* If you want to blur image
*/
// image = blurImage(image);
return resize(image, width, height);
}

public static BufferedImage blurImage(BufferedImage image) {
float ninth = 1.0f / 9.0f;
float[] blurKernel = { ninth, ninth, ninth, ninth, ninth, ninth, ninth,
ninth, ninth };

Map map = new HashMap();
map.put(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
map.put(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
map.put(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
RenderingHints hints = new RenderingHints(map);
BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, blurKernel),
ConvolveOp.EDGE_NO_OP, hints);
return op.filter(image, null);
}

private static BufferedImage createCompatibleImage(BufferedImage image) {
GraphicsConfiguration gc = BufferedImageGraphicsConfig.getConfig(image);
int w = image.getWidth();
int h = image.getHeight();
BufferedImage result = gc.createCompatibleImage(w, h,
Transparency.TRANSLUCENT);
Graphics2D g2 = result.createGraphics();
g2.drawRenderedImage(image, null);
g2.dispose();
return result;
}

}

Advertisements

Capture/Grab Website in Java

I have got a requirement in one of my Product to capture a website and Transform it to our custom defined one. As i’m Java Evangelist i tried to see if there are any Libraries over the web which help me do that I have choosen to use HTMLParser to parse Webpages and then use it to Capture Website in Java

If you go through HTMLParser you will actually go through following concepts

Extraction

  1. text extraction, for use as input for text search engine databases for example
  2. link extraction, for crawling through web pages or harvesting email addresses
  3. screen scraping, for programmatic data input from web pages
  4. resource extraction, collecting images or sound
  5. a browser front end, the preliminary stage of page display
  6. link checking, ensuring links are valid
  7. site monitoring, checking for page differences beyond simplistic diffs

Transformation

  1. URL rewriting, modifying some or all links on a page
  2. site capture, moving content from the web to local disk
  3. censorship, removing offending words and phrases from pages
  4. HTML cleanup, correcting erroneous pages
  5. ad removal, excising URLs referencing advertising
  6. conversion to XML, moving existing web pages to XML

During or after reading in a page, operations on the nodes can accomplish many transformation tasks “in place”, which can then be output with the toHtml() method. Depending on the purpose of your application, you will probably want to look into node decorators, visitors, or custom tags in conjunction with the PrototypicalNodeFactory.

Steps Required to Create Website Capturer Code

  1. First Get the Index Page
  2. Scan all Stylesheets
  3. Scan all Resource links in page
  4. Scan all JavaScript Links in Page
  5. For each stylesheet download any resource links in stylesheet definitions

I would present an example Using HTMLParser as utitlity to parse HTML

Here are high level steps

  • Initialize Parser/Factory and Filters
    mParser = new Parser();
    factory = new PrototypicalNodeFactory();
    factory.registerTag(new LocalLinkTag());
    factory.registerTag(new LocalFrameTag());
    factory.registerTag(new LocalBaseHrefTag());
    factory.registerTag(new LocalImageTag());
    factory.registerTag(new LocalScriptTag());
    factory.registerTag(new LocalStyleTag());
  • Get the URL of website to be captured and Directory where captured website have to be stored from user
  • For each page Do the following
    // Download Process page and relink all links to local links in HTML
    process(getFilter());
    // Download and store scripts
    while (0 != mScripts.size())
    copyScripts();
    // Download and store stylesheets
    while (0 != mStyleSheets.size())
    copyStyleSheets();
    // While processing stylesheets also download any image references in stylesheets. If yes add them to download list to get them downloaded
    // Download and store images
    while (0 != mImages.size())
    copyImages();

    You can downlod

    https://linkwithweb.googlecode.com/svn/trunk/Web2Mobile

    and run LinkwithwebSiteCapturer.java from eclipse. The project is mavenized so if you run following commands you are good to go

    mvn eclipse:clean eclipse:eclipse
    and then open up your eclipse and run
    LinkwithwebSiteCapturer

    Any Queries mail to ashwin@linkwithweb.com