Java/2D Graphics GUI/BufferedImage — различия между версиями
Admin (обсуждение | вклад) м (1 версия) |
|
(нет различий)
|
Текущая версия на 06:53, 1 июня 2010
Содержание
- 1 Animated clipping of an image and shapes with alpha
- 2 Blurring a Buffered Image
- 3 BufferedImage with Jumbled images
- 4 BufferImage based Label
- 5 Compositing is the combining of elements from separate sources into single images
- 6 Constructs a BufferedImage with a linear sRGB colorModel, and alpha
- 7 Convert a non-RGB image to an RGB buffered image
- 8 Converting a Colored Buffered Image to Gray
- 9 Create a buffered image that supports transparency
- 10 Create buffered image that does not support transparency
- 11 Create Headless BufferedImage
- 12 Creates and returns a buffered version of the specified image.
- 13 Creating a BufferedImage from an Image object
- 14 Display image after operation
- 15 Get average of a set of images with WritableRaster
- 16 Make Linear Buffered Image
- 17 Renders an ellipse overlapping a rectangle with the compositing rule and alpha value selected by the user
- 18 Renders multiple paragraphs of text in an array to an image (created and returned).
- 19 Save an image after operations
- 20 Scale, convert images
- 21 Sharpening a Buffered Image
Animated clipping of an image and shapes with alpha
/*
* Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.RenderingHints;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.swing.JApplet;
import javax.swing.JFrame;
/**
* Animated clipping of an image & shapes with alpha.
*/
public class ClipImage extends JApplet implements Runnable {
private Image img;
private final double OINC[] = { 5.0, 3.0 };
private final double SINC[] = { 5.0, 5.0 };
private double x, y;
private double ix = OINC[0];
private double iy = OINC[1];
private double iw = SINC[0];
private double ih = SINC[1];
private double ew, eh; // ellipse width & height
private GeneralPath p = new GeneralPath();
private AffineTransform at = new AffineTransform();
private BasicStroke bs = new BasicStroke(20.0f);
private Arc2D arc = new Arc2D.Float();
private Ellipse2D ellipse = new Ellipse2D.Float();
private RoundRectangle2D roundRect = new RoundRectangle2D.Float();
private Rectangle2D rect = new Rectangle2D.Float();
private Color redBlend = new Color(255, 0, 0, 120);
private Color greenBlend = new Color(0, 255, 0, 120);
private Thread thread;
private BufferedImage offImg;
private int w, h;
private boolean newBufferedImage;
public void init() {
setBackground(Color.white);
img = getImage(getURL("images/clouds.jpg"));
try {
MediaTracker tracker = new MediaTracker(this);
tracker.addImage(img, 0);
tracker.waitForID(0);
} catch (Exception e) {
}
}
public void drawDemo(Graphics2D g2) {
if (newBufferedImage) {
x = Math.random() * w;
y = Math.random() * h;
ew = (Math.random() * w) / 2;
eh = (Math.random() * h) / 2;
}
x += ix;
y += iy;
ew += iw;
eh += ih;
if (ew > w / 2) {
ew = w / 2;
iw = Math.random() * -w / 16 - 1;
}
if (ew < w / 8) {
ew = w / 8;
iw = Math.random() * w / 16 + 1;
}
if (eh > h / 2) {
eh = h / 2;
ih = Math.random() * -h / 16 - 1;
}
if (eh < h / 8) {
eh = h / 8;
ih = Math.random() * h / 16 + 1;
}
if ((x + ew) > w) {
x = (w - ew) - 1;
ix = Math.random() * -w / 32 - 1;
}
if (x < 0) {
x = 2;
ix = Math.random() * w / 32 + 1;
}
if ((y + eh) > h) {
y = (h - eh) - 2;
iy = Math.random() * -h / 32 - 1;
}
if (y < 0) {
y = 2;
iy = Math.random() * h / 32 + 1;
}
ellipse.setFrame(x, y, ew, eh);
g2.setClip(ellipse);
rect.setRect(x + 5, y + 5, ew - 10, eh - 10);
g2.clip(rect);
g2.drawImage(img, 0, 0, w, h, this);
p.reset();
p.moveTo(-w / 2.0f, -h / 8.0f);
p.lineTo(+w / 2.0f, -h / 8.0f);
p.lineTo(-w / 4.0f, +h / 2.0f);
p.lineTo(+0.0f, -h / 2.0f);
p.lineTo(+w / 4.0f, +h / 2.0f);
p.closePath();
at.setToIdentity();
at.translate(w * .5f, h * .5f);
g2.transform(at);
g2.setStroke(bs);
g2.setPaint(redBlend);
g2.draw(p);
at.setToIdentity();
g2.setTransform(at);
g2.setPaint(greenBlend);
for (int yy = 0; yy < h; yy += 50) {
for (int xx = 0, i = 0; xx < w; i++, xx += 50) {
switch (i) {
case 0:
arc.setArc(xx, yy, 25, 25, 45, 270, Arc2D.PIE);
g2.fill(arc);
break;
case 1:
ellipse.setFrame(xx, yy, 25, 25);
g2.fill(ellipse);
break;
case 2:
roundRect.setRoundRect(xx, yy, 25, 25, 4, 4);
g2.fill(roundRect);
break;
case 3:
rect.setRect(xx, yy, 25, 25);
g2.fill(rect);
i = -1;
}
}
}
}
public Graphics2D createDemoGraphics2D(Graphics g) {
Graphics2D g2 = null;
if (offImg == null || offImg.getWidth() != w || offImg.getHeight() != h) {
offImg = (BufferedImage) createImage(w, h);
newBufferedImage = true;
}
if (offImg != null) {
g2 = offImg.createGraphics();
g2.setBackground(getBackground());
}
// .. set attributes ..
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
// .. clear canvas ..
g2.clearRect(0, 0, w, h);
return g2;
}
public void paint(Graphics g) {
w = getWidth();
h = getHeight();
if (w <= 0 || h <= 0)
return;
Graphics2D g2 = createDemoGraphics2D(g);
drawDemo(g2);
g2.dispose();
if (offImg != null && isShowing()) {
g.drawImage(offImg, 0, 0, this);
}
newBufferedImage = false;
}
public void start() {
thread = new Thread(this);
thread.start();
}
public synchronized void stop() {
thread = null;
}
public void run() {
Thread me = Thread.currentThread();
while (thread == me && isShowing()) {
Graphics g = getGraphics();
paint(g);
g.dispose();
thread.yield();
}
thread = null;
}
protected URL getURL(String filename) {
URL codeBase = this.getCodeBase();
URL url = null;
try {
url = new URL(codeBase, filename);
} catch (java.net.MalformedURLException e) {
System.out.println("Couldn"t create image: " + "badly specified URL");
return null;
}
return url;
}
public static void main(String s[]) {
final ClipImage demo = new ClipImage();
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowDeiconified(WindowEvent e) {
demo.start();
}
public void windowIconified(WindowEvent e) {
demo.stop();
}
};
JFrame f = new JFrame("Java 2D Demo - ClipImage");
f.addWindowListener(l);
f.getContentPane().add("Center", demo);
f.setSize(new Dimension(400, 300));
f.setVisible(true);
demo.start();
}
}
Blurring a Buffered Image
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
public class Main {
public static void main(String[] argv) throws Exception {
BufferedImage bufferedImage = new BufferedImage(200, 200,
BufferedImage.TYPE_BYTE_INDEXED);
Kernel kernel = new Kernel(3, 3, new float[] { 1f / 9f, 1f / 9f, 1f / 9f,
1f / 9f, 1f / 9f, 1f / 9f, 1f / 9f, 1f / 9f, 1f / 9f });
BufferedImageOp op = new ConvolveOp(kernel);
bufferedImage = op.filter(bufferedImage, null);
}
}
BufferedImage with Jumbled images
/*
* Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.imageio.*;
import javax.swing.*;
import java.util.Random;
class JumbledImage extends Component {
private int numlocs = 2;
private int numcells = numlocs*numlocs;
private int[] cells;
private BufferedImage bi;
int w, h, cw, ch;
public JumbledImage(URL imageSrc) {
try {
bi = ImageIO.read(imageSrc);
w = bi.getWidth(null);
h = bi.getHeight(null);
} catch (IOException e) {
System.out.println("Image could not be read");
System.exit(1);
}
cw = w/numlocs;
ch = h/numlocs;
cells = new int[numcells];
for (int i=0;i<numcells;i++) {
cells[i] = i;
}
}
void jumble() {
Random rand = new Random();
int ri;
for (int i=0; i<numcells; i++) {
while ((ri = rand.nextInt(numlocs)) == i);
int tmp = cells[i];
cells[i] = cells[ri];
cells[ri] = tmp;
}
}
public Dimension getPreferredSize() {
return new Dimension(w, h);
}
public void paint(Graphics g) {
int dx, dy;
for (int x=0; x<numlocs; x++) {
int sx = x*cw;
for (int y=0; y<numlocs; y++) {
int sy = y*ch;
int cell = cells[x*numlocs+y];
dx = (cell / numlocs) * cw;
dy = (cell % numlocs) * ch;
g.drawImage(bi,
dx, dy, dx+cw, dy+ch,
sx, sy, sx+cw, sy+ch,
null);
}
}
}
}
public class JumbledImageApplet extends JApplet {
static String imageFileName = "duke_skateboard.jpg";
private URL imageSrc;
private JumbledImage jumbledImage;
public JumbledImageApplet () {
}
public JumbledImageApplet (URL imageSrc) {
this.imageSrc = imageSrc;
}
public void init() {
try {
imageSrc = new URL(getCodeBase(), imageFileName);
} catch (MalformedURLException e) {
}
buildUI();
}
public void buildUI() {
final JumbledImage ji = new JumbledImage(imageSrc);
add("Center", ji);
JButton jumbleButton = new JButton("Jumble");
jumbleButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JButton b = (JButton)e.getSource();
ji.jumble();
ji.repaint();
};
});
Dimension jumbleSize = ji.getPreferredSize();
resize(jumbleSize.width, jumbleSize.height+40);
add("South", jumbleButton);
}
public static void main(String s[]) {
JFrame f = new JFrame("Jumbled Image");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
URL imageSrc = null;
try {
imageSrc = ((new File(imageFileName)).toURI()).toURL();
} catch (MalformedURLException e) {
}
JumbledImageApplet jumbler = new JumbledImageApplet(imageSrc);
jumbler.buildUI();
f.add("Center", jumbler);
f.pack();
f.setVisible(true);
}
}
BufferImage based Label
/*
* Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.awt.Color;
import java.awt.ruponent;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
public class ImageLabel extends Component {
public static void main(String args[]) {
JFrame frame = new JFrame("Image Label");
BufferedImage img = null;
try {
String imageFileName = "painting.gif";
img = ImageIO.read(new File(imageFileName));
} catch (IOException e) {
}
frame.add("Center", new ImageLabel(img, "Java 2D Graphics!"));
frame.pack();
frame.setVisible(true);
}
BufferedImage img;
String text;
Font font;
public ImageLabel(BufferedImage img, String text) {
this.img = img;
this.text = text;
font = new Font("Serif", Font.PLAIN, 36);
}
/* We want to size the component around the text. */
public Dimension getPreferredSize() {
FontMetrics metrics = img.getGraphics().getFontMetrics(font);
int width = metrics.stringWidth(text) * 2;
int height = metrics.getHeight() * 2;
return new Dimension(width, height);
}
public void paint(Graphics g) {
/*
* Draw the image stretched to exactly cover the size of the drawing area.
*/
Dimension size = getSize();
g.drawImage(img, 0, 0, size.width, size.height, 0, 0, img.getWidth(null),
img.getHeight(null), null);
/*
* Fill a rounded rectangle centered in the drawing area. Calculate the size
* of the rectangle from the size of the text
*/
g.setFont(font);
FontRenderContext frc = ((Graphics2D) g).getFontRenderContext();
Rectangle2D bounds = font.getStringBounds(text, frc);
int wText = (int) bounds.getWidth();
int hText = (int) bounds.getHeight();
int rX = (size.width - wText) / 2;
int rY = (size.height - hText) / 2;
g.setColor(Color.yellow);
g.fillRoundRect(rX, rY, wText, hText, hText / 2, hText / 2);
/*
* Draw text positioned in the rectangle. Since the rectangle is sized based
* on the bounds of the String we can position it using those bounds.
*/
int xText = rX - (int) bounds.getX();
int yText = rY - (int) bounds.getY();
g.setColor(Color.black);
g.setFont(font);
g.drawString(text, xText, yText);
}
}
Compositing is the combining of elements from separate sources into single images
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class CompositingDST extends JPanel {
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.DST, 0.5f);
BufferedImage buffImg = new BufferedImage(60, 60, BufferedImage.TYPE_INT_ARGB);
Graphics2D gbi = buffImg.createGraphics();
gbi.setPaint(Color.red);
gbi.fillRect(10, 10, 40, 40);
gbi.setComposite(ac);
gbi.setPaint(Color.green);
gbi.fillRect(5, 5, 40, 40);
g2d.drawImage(buffImg, 20, 20, null);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Composition");
frame.add(new CompositingDST());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 120);
frame.setVisible(true);
}
}
Constructs a BufferedImage with a linear sRGB colorModel, and alpha
/*
Copyright 2001-2004 The Apache Software Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import java.awt.ruposite;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ruponentSampleModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBufferShort;
import java.awt.image.DataBufferUShort;
import java.awt.image.DirectColorModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.WritableRaster;
import java.awt.image.renderable.RenderContext;
import java.awt.image.renderable.RenderableImage;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
/*
import org.apache.batik.ext.awt.RenderingHintsKeyExt;
import org.apache.batik.ext.awt.image.renderable.PaintRable;
import org.apache.batik.ext.awt.image.rendered.AffineRed;
import org.apache.batik.ext.awt.image.rendered.Any2LsRGBRed;
import org.apache.batik.ext.awt.image.rendered.Any2sRGBRed;
import org.apache.batik.ext.awt.image.rendered.BufferedImageCachableRed;
import org.apache.batik.ext.awt.image.rendered.CachableRed;
import org.apache.batik.ext.awt.image.rendered.FormatRed;
import org.apache.batik.ext.awt.image.rendered.RenderedImageCachableRed;
import org.apache.batik.ext.awt.image.rendered.TranslateRed;
*/
/**
* Set of utility methods for Graphics.
* These generally bypass broken methods in Java2D or provide tweaked
* implementations.
*
* @author
* @version $Id: GraphicsUtil.java,v 1.36 2005/03/27 08:58:32 cam Exp $
*/
public class GraphicsUtil {
public static AffineTransform IDENTITY = new AffineTransform();
/**
* Standard prebuilt Linear_sRGB color model with no alpha.
*/
public final static ColorModel Linear_sRGB =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_LINEAR_RGB), 24,
0x00FF0000, 0x0000FF00,
0x000000FF, 0x0, false,
DataBuffer.TYPE_INT);
/**
* Standard prebuilt Linear_sRGB color model with premultiplied alpha.
*/
public final static ColorModel Linear_sRGB_Pre =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_LINEAR_RGB), 32,
0x00FF0000, 0x0000FF00,
0x000000FF, 0xFF000000, true,
DataBuffer.TYPE_INT);
/**
* Standard prebuilt Linear_sRGB color model with unpremultiplied alpha.
*/
public final static ColorModel Linear_sRGB_Unpre =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_LINEAR_RGB), 32,
0x00FF0000, 0x0000FF00,
0x000000FF, 0xFF000000, false,
DataBuffer.TYPE_INT);
/**
* Standard prebuilt sRGB color model with no alpha.
*/
public final static ColorModel sRGB =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_sRGB), 24,
0x00FF0000, 0x0000FF00,
0x000000FF, 0x0, false,
DataBuffer.TYPE_INT);
/**
* Standard prebuilt sRGB color model with premultiplied alpha.
*/
public final static ColorModel sRGB_Pre =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_sRGB), 32,
0x00FF0000, 0x0000FF00,
0x000000FF, 0xFF000000, true,
DataBuffer.TYPE_INT);
/**
* Standard prebuilt sRGB color model with unpremultiplied alpha.
*/
public final static ColorModel sRGB_Unpre =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_sRGB), 32,
0x00FF0000, 0x0000FF00,
0x000000FF, 0xFF000000, false,
DataBuffer.TYPE_INT);
/**
* Method that returns either Linear_sRGB_Pre or Linear_sRGB_UnPre
* based on premult flag.
* @param premult True if the ColorModel should have premultiplied alpha.
* @return a ColorMdoel with Linear sRGB colorSpace and
* the alpha channel set in accordance with
* <tt>premult</tt>
*/
public static ColorModel makeLinear_sRGBCM(boolean premult) {
if (premult)
return Linear_sRGB_Pre;
return Linear_sRGB_Unpre;
}
/**
* Constructs a BufferedImage with a linear sRGB colorModel, and alpha.
* @param width The desired width of the BufferedImage
* @param height The desired height of the BufferedImage
* @param premult The desired state of alpha premultiplied
* @return The requested BufferedImage.
*/
public static BufferedImage makeLinearBufferedImage(int width,
int height,
boolean premult) {
ColorModel cm = makeLinear_sRGBCM(premult);
WritableRaster wr = cm.createCompatibleWritableRaster(width, height);
return new BufferedImage(cm, wr, premult, null);
}
/**
* Creates a new raster that has a <b>copy</b> of the data in
* <tt>ras</tt>. This is highly optimized for speed. There is
* no provision for changing any aspect of the SampleModel.
*
* This method should be used when you need to change the contents
* of a Raster that you do not "own" (ie the result of a
* <tt>getData</tt> call).
* @param ras The Raster to copy.
* @return A writable copy of <tt>ras</tt>
*/
public static WritableRaster copyRaster(Raster ras) {
return copyRaster(ras, ras.getMinX(), ras.getMinY());
}
/**
* Creates a new raster that has a <b>copy</b> of the data in
* <tt>ras</tt>. This is highly optimized for speed. There is
* no provision for changing any aspect of the SampleModel.
* However you can specify a new location for the returned raster.
*
* This method should be used when you need to change the contents
* of a Raster that you do not "own" (ie the result of a
* <tt>getData</tt> call).
*
* @param ras The Raster to copy.
*
* @param minX The x location for the upper left corner of the
* returned WritableRaster.
*
* @param minY The y location for the upper left corner of the
* returned WritableRaster.
*
* @return A writable copy of <tt>ras</tt>
*/
public static WritableRaster copyRaster(Raster ras, int minX, int minY) {
WritableRaster ret = Raster.createWritableRaster
(ras.getSampleModel(),
new Point(0,0));
ret = ret.createWritableChild
(ras.getMinX()-ras.getSampleModelTranslateX(),
ras.getMinY()-ras.getSampleModelTranslateY(),
ras.getWidth(), ras.getHeight(),
minX, minY, null);
// Use System.arraycopy to copy the data between the two...
DataBuffer srcDB = ras.getDataBuffer();
DataBuffer retDB = ret.getDataBuffer();
if (srcDB.getDataType() != retDB.getDataType()) {
throw new IllegalArgumentException
("New DataBuffer doesn"t match original");
}
int len = srcDB.getSize();
int banks = srcDB.getNumBanks();
int [] offsets = srcDB.getOffsets();
for (int b=0; b< banks; b++) {
switch (srcDB.getDataType()) {
case DataBuffer.TYPE_BYTE: {
DataBufferByte srcDBT = (DataBufferByte)srcDB;
DataBufferByte retDBT = (DataBufferByte)retDB;
System.arraycopy(srcDBT.getData(b), offsets[b],
retDBT.getData(b), offsets[b], len);
}
case DataBuffer.TYPE_INT: {
DataBufferInt srcDBT = (DataBufferInt)srcDB;
DataBufferInt retDBT = (DataBufferInt)retDB;
System.arraycopy(srcDBT.getData(b), offsets[b],
retDBT.getData(b), offsets[b], len);
}
case DataBuffer.TYPE_SHORT: {
DataBufferShort srcDBT = (DataBufferShort)srcDB;
DataBufferShort retDBT = (DataBufferShort)retDB;
System.arraycopy(srcDBT.getData(b), offsets[b],
retDBT.getData(b), offsets[b], len);
}
case DataBuffer.TYPE_USHORT: {
DataBufferUShort srcDBT = (DataBufferUShort)srcDB;
DataBufferUShort retDBT = (DataBufferUShort)retDB;
System.arraycopy(srcDBT.getData(b), offsets[b],
retDBT.getData(b), offsets[b], len);
}
}
}
return ret;
}
/**
* Coerces <tt>ras</tt> to be writable. The returned Raster continues to
* reference the DataBuffer from ras, so modifications to the returned
* WritableRaster will be seen in ras.<p>
*
* This method should only be used if you need a WritableRaster due to
* an interface (such as to construct a BufferedImage), but have no
* intention of modifying the contents of the returned Raster. If
* you have any doubt about other users of the data in <tt>ras</tt>,
* use copyRaster (above).
* @param ras The raster to make writable.
* @return A Writable version of ras (shares DataBuffer with
* <tt>ras</tt>).
*/
public static WritableRaster makeRasterWritable(Raster ras) {
return makeRasterWritable(ras, ras.getMinX(), ras.getMinY());
}
/**
* Coerces <tt>ras</tt> to be writable. The returned Raster continues to
* reference the DataBuffer from ras, so modifications to the returned
* WritableRaster will be seen in ras.<p>
*
* You can specify a new location for the returned WritableRaster, this
* is especially useful for constructing BufferedImages which require
* the Raster to be at (0,0).
*
* This method should only be used if you need a WritableRaster due to
* an interface (such as to construct a BufferedImage), but have no
* intention of modifying the contents of the returned Raster. If
* you have any doubt about other users of the data in <tt>ras</tt>,
* use copyRaster (above).
*
* @param ras The raster to make writable.
*
* @param minX The x location for the upper left corner of the
* returned WritableRaster.
*
* @param minY The y location for the upper left corner of the
* returned WritableRaster.
*
* @return A Writable version of <tT>ras</tt> with it"s upper left
* hand coordinate set to minX, minY (shares it"s DataBuffer
* with <tt>ras</tt>).
*/
public static WritableRaster makeRasterWritable(Raster ras,
int minX, int minY) {
WritableRaster ret = Raster.createWritableRaster
(ras.getSampleModel(),
ras.getDataBuffer(),
new Point(0,0));
ret = ret.createWritableChild
(ras.getMinX()-ras.getSampleModelTranslateX(),
ras.getMinY()-ras.getSampleModelTranslateY(),
ras.getWidth(), ras.getHeight(),
minX, minY, null);
return ret;
}
/**
* Create a new ColorModel with it"s alpha premultiplied state matching
* newAlphaPreMult.
* @param cm The ColorModel to change the alpha premult state of.
* @param newAlphaPreMult The new state of alpha premult.
* @return A new colorModel that has isAlphaPremultiplied()
* equal to newAlphaPreMult.
*/
public static ColorModel
coerceColorModel(ColorModel cm, boolean newAlphaPreMult) {
if (cm.isAlphaPremultiplied() == newAlphaPreMult)
return cm;
// Easiest way to build proper colormodel for new Alpha state...
// Eventually this should switch on known ColorModel types and
// only fall back on this hack when the CM type is unknown.
WritableRaster wr = cm.createCompatibleWritableRaster(1,1);
return cm.coerceData(wr, newAlphaPreMult);
}
/**
* Coerces data within a bufferedImage to match newAlphaPreMult,
* Note that this can not change the colormodel of bi so you
*
* @param wr The raster to change the state of.
* @param cm The colormodel currently associated with data in wr.
* @param newAlphaPreMult The desired state of alpha Premult for raster.
* @return A new colormodel that matches newAlphaPreMult.
*/
public static ColorModel
coerceData(WritableRaster wr, ColorModel cm, boolean newAlphaPreMult) {
// System.out.println("CoerceData: " + cm.isAlphaPremultiplied() +
// " Out: " + newAlphaPreMult);
if (cm.hasAlpha()== false)
// Nothing to do no alpha channel
return cm;
if (cm.isAlphaPremultiplied() == newAlphaPreMult)
// nothing to do alpha state matches...
return cm;
// System.out.println("CoerceData: " + wr.getSampleModel());
if (newAlphaPreMult) {
multiplyAlpha(wr);
} else {
divideAlpha(wr);
}
return coerceColorModel(cm, newAlphaPreMult);
}
public static void multiplyAlpha(WritableRaster wr) {
if (is_BYTE_COMP_Data(wr.getSampleModel()))
mult_BYTE_COMP_Data(wr);
else if (is_INT_PACK_Data(wr.getSampleModel(), true))
mult_INT_PACK_Data(wr);
else {
int [] pixel = null;
int bands = wr.getNumBands();
float norm = 1f/255f;
int x0, x1, y0, y1, a, b;
float alpha;
x0 = wr.getMinX();
x1 = x0+wr.getWidth();
y0 = wr.getMinY();
y1 = y0+wr.getHeight();
for (int y=y0; y<y1; y++)
for (int x=x0; x<x1; x++) {
pixel = wr.getPixel(x,y,pixel);
a = pixel[bands-1];
if ((a >= 0) && (a < 255)) {
alpha = a*norm;
for (b=0; b<bands-1; b++)
pixel[b] = (int)(pixel[b]*alpha+0.5f);
wr.setPixel(x,y,pixel);
}
}
}
}
public static void divideAlpha(WritableRaster wr) {
if (is_BYTE_COMP_Data(wr.getSampleModel()))
divide_BYTE_COMP_Data(wr);
else if (is_INT_PACK_Data(wr.getSampleModel(), true))
divide_INT_PACK_Data(wr);
else {
int x0, x1, y0, y1, a, b;
float ialpha;
int bands = wr.getNumBands();
int [] pixel = null;
x0 = wr.getMinX();
x1 = x0+wr.getWidth();
y0 = wr.getMinY();
y1 = y0+wr.getHeight();
for (int y=y0; y<y1; y++)
for (int x=x0; x<x1; x++) {
pixel = wr.getPixel(x,y,pixel);
a = pixel[bands-1];
if ((a > 0) && (a < 255)) {
ialpha = 255/(float)a;
for (b=0; b<bands-1; b++)
pixel[b] = (int)(pixel[b]*ialpha+0.5f);
wr.setPixel(x,y,pixel);
}
}
}
}
public static boolean is_INT_PACK_Data(SampleModel sm,
boolean requireAlpha) {
// Check ColorModel is of type DirectColorModel
if(!(sm instanceof SinglePixelPackedSampleModel)) return false;
// Check transfer type
if(sm.getDataType() != DataBuffer.TYPE_INT) return false;
SinglePixelPackedSampleModel sppsm;
sppsm = (SinglePixelPackedSampleModel)sm;
int [] masks = sppsm.getBitMasks();
if (masks.length == 3) {
if (requireAlpha) return false;
} else if (masks.length != 4)
return false;
if(masks[0] != 0x00ff0000) return false;
if(masks[1] != 0x0000ff00) return false;
if(masks[2] != 0x000000ff) return false;
if ((masks.length == 4) &&
(masks[3] != 0xff000000)) return false;
return true;
}
public static boolean is_BYTE_COMP_Data(SampleModel sm) {
// Check ColorModel is of type DirectColorModel
if(!(sm instanceof ComponentSampleModel)) return false;
// Check transfer type
if(sm.getDataType() != DataBuffer.TYPE_BYTE) return false;
return true;
}
protected static void divide_INT_PACK_Data(WritableRaster wr) {
// System.out.println("Divide Int");
SinglePixelPackedSampleModel sppsm;
sppsm = (SinglePixelPackedSampleModel)wr.getSampleModel();
final int width = wr.getWidth();
final int scanStride = sppsm.getScanlineStride();
DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
final int base
= (db.getOffset() +
sppsm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(),
wr.getMinY()-wr.getSampleModelTranslateY()));
int pixel, a, aFP;
// Access the pixel data array
final int pixels[] = db.getBankData()[0];
for (int y=0; y<wr.getHeight(); y++) {
int sp = base + y*scanStride;
final int end = sp + width;
while (sp < end) {
pixel = pixels[sp];
a = pixel>>>24;
if (a<=0) {
pixels[sp] = 0x00FFFFFF;
}
else if (a<255) {
aFP = (0x00FF0000/a);
pixels[sp] =
((a << 24) |
(((((pixel&0xFF0000)>>16)*aFP)&0xFF0000) ) |
(((((pixel&0x00FF00)>>8) *aFP)&0xFF0000)>>8 ) |
(((((pixel&0x0000FF)) *aFP)&0xFF0000)>>16));
}
sp++;
}
}
}
protected static void mult_INT_PACK_Data(WritableRaster wr) {
// System.out.println("Multiply Int: " + wr);
SinglePixelPackedSampleModel sppsm;
sppsm = (SinglePixelPackedSampleModel)wr.getSampleModel();
final int width = wr.getWidth();
final int scanStride = sppsm.getScanlineStride();
DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
final int base
= (db.getOffset() +
sppsm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(),
wr.getMinY()-wr.getSampleModelTranslateY()));
// Access the pixel data array
final int pixels[] = db.getBankData()[0];
for (int y=0; y<wr.getHeight(); y++) {
int sp = base + y*scanStride;
final int end = sp + width;
while (sp < end) {
int pixel = pixels[sp];
int a = pixel>>>24;
if ((a>=0) && (a<255)) {
pixels[sp] = ((a << 24) |
((((pixel&0xFF0000)*a)>>8)&0xFF0000) |
((((pixel&0x00FF00)*a)>>8)&0x00FF00) |
((((pixel&0x0000FF)*a)>>8)&0x0000FF));
}
sp++;
}
}
}
protected static void divide_BYTE_COMP_Data(WritableRaster wr) {
// System.out.println("Multiply Int: " + wr);
ComponentSampleModel csm;
csm = (ComponentSampleModel)wr.getSampleModel();
final int width = wr.getWidth();
final int scanStride = csm.getScanlineStride();
final int pixStride = csm.getPixelStride();
final int [] bandOff = csm.getBandOffsets();
DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
final int base
= (db.getOffset() +
csm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(),
wr.getMinY()-wr.getSampleModelTranslateY()));
int a=0;
int aOff = bandOff[bandOff.length-1];
int bands = bandOff.length-1;
int b, i;
// Access the pixel data array
final byte pixels[] = db.getBankData()[0];
for (int y=0; y<wr.getHeight(); y++) {
int sp = base + y*scanStride;
final int end = sp + width*pixStride;
while (sp < end) {
a = pixels[sp+aOff]&0xFF;
if (a==0) {
for (b=0; b<bands; b++)
pixels[sp+bandOff[b]] = (byte)0xFF;
} else if (a<255) {
int aFP = (0x00FF0000/a);
for (b=0; b<bands; b++) {
i = sp+bandOff[b];
pixels[i] = (byte)(((pixels[i]&0xFF)*aFP)>>>16);
}
}
sp+=pixStride;
}
}
}
protected static void mult_BYTE_COMP_Data(WritableRaster wr) {
// System.out.println("Multiply Int: " + wr);
ComponentSampleModel csm;
csm = (ComponentSampleModel)wr.getSampleModel();
final int width = wr.getWidth();
final int scanStride = csm.getScanlineStride();
final int pixStride = csm.getPixelStride();
final int [] bandOff = csm.getBandOffsets();
DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
final int base
= (db.getOffset() +
csm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(),
wr.getMinY()-wr.getSampleModelTranslateY()));
int a=0;
int aOff = bandOff[bandOff.length-1];
int bands = bandOff.length-1;
int b, i;
// Access the pixel data array
final byte pixels[] = db.getBankData()[0];
for (int y=0; y<wr.getHeight(); y++) {
int sp = base + y*scanStride;
final int end = sp + width*pixStride;
while (sp < end) {
a = pixels[sp+aOff]&0xFF;
if (a!=0xFF)
for (b=0; b<bands; b++) {
i = sp+bandOff[b];
pixels[i] = (byte)(((pixels[i]&0xFF)*a)>>8);
}
sp+=pixStride;
}
}
}
/*
This is skanky debugging code that might be useful in the future:
if (count == 33) {
String label = "sub [" + x + ", " + y + "]: ";
org.ImageDisplay.showImage
(label, subBI);
org.ImageDisplay.printImage
(label, subBI,
new Rectangle(75-iR.x, 90-iR.y, 32, 32));
}
// if ((count++ % 50) == 10)
// org.ImageDisplay.showImage("foo: ", subBI);
Graphics2D realG2D = g2d;
while (realG2D instanceof sun.java2d.ProxyGraphics2D) {
realG2D = ((sun.java2d.ProxyGraphics2D)realG2D).getDelegate();
}
if (realG2D instanceof sun.awt.image.BufferedImageGraphics2D) {
count++;
if (count == 34) {
RenderedImage ri;
ri = ((sun.awt.image.BufferedImageGraphics2D)realG2D).bufImg;
// g2d.setComposite(SVGComposite.OVER);
// org.ImageDisplay.showImage("Bar: " + count, cr);
org.ImageDisplay.printImage("Bar: " + count, cr,
new Rectangle(75, 90, 32, 32));
org.ImageDisplay.showImage ("Foo: " + count, ri);
org.ImageDisplay.printImage("Foo: " + count, ri,
new Rectangle(75, 90, 32, 32));
System.out.println("BI: " + ri);
System.out.println("BISM: " + ri.getSampleModel());
System.out.println("BICM: " + ri.getColorModel());
System.out.println("BICM class: " + ri.getColorModel().getClass());
System.out.println("BICS: " + ri.getColorModel().getColorSpace());
System.out.println
("sRGB CS: " +
ColorSpace.getInstance(ColorSpace.CS_sRGB));
System.out.println("G2D info");
System.out.println("\tComposite: " + g2d.getComposite());
System.out.println("\tTransform" + g2d.getTransform());
java.awt.RenderingHints rh = g2d.getRenderingHints();
java.util.Set keys = rh.keySet();
java.util.Iterator iter = keys.iterator();
while (iter.hasNext()) {
Object o = iter.next();
System.out.println("\t" + o.toString() + " -> " +
rh.get(o).toString());
}
ri = cr;
System.out.println("RI: " + ri);
System.out.println("RISM: " + ri.getSampleModel());
System.out.println("RICM: " + ri.getColorModel());
System.out.println("RICM class: " + ri.getColorModel().getClass());
System.out.println("RICS: " + ri.getColorModel().getColorSpace());
}
}
*/
}
Convert a non-RGB image to an RGB buffered image
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
public class Main {
public static void main(String[] argv) throws Exception {
Image image = new ImageIcon("image.gif").getImage();
BufferedImage bimage = new BufferedImage(image.getWidth(null), image
.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics2D g = bimage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
}
}
Converting a Colored Buffered Image to Gray
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
public class Main {
public static void main(String[] argv) throws Exception {
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
ColorConvertOp op = new ColorConvertOp(cs, null);
BufferedImage bufferedImage = new BufferedImage(200, 200,
BufferedImage.TYPE_BYTE_INDEXED);
bufferedImage = op.filter(bufferedImage, null);
}
}
Create a buffered image that supports transparency
import java.awt.image.BufferedImage;
public class Main {
public static void main(String[] argv) throws Exception {
int width = 100;
int height = 100;
BufferedImage bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
}
}
Create buffered image that does not support transparency
import java.awt.image.BufferedImage;
public class Main {
public static void main(String[] argv) throws Exception {
int width = 100;
int height = 100;
BufferedImage bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
}
}
Create Headless BufferedImage
/*
* Copyright (c) JForum Team
* All rights reserved.
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
* 1) Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
* 2) Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* 3) Neither the name of "Rafael Steil" nor
* the names of its contributors may be used to endorse
* or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
* HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
*
* This file creation date: 21/04/2004 - 19:54:16
* The JForum Project
* http://www.jforum.net
*/
import java.awt.Dimension;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Locale;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
/**
* Utilities methods for image manipulation. It does not support writting of GIF images, but it can
* read from. GIF images will be saved as PNG.
*
* @author Rafael Steil
* @version $Id: ImageUtils.java,v 1.23 2007/09/09 01:05:22 rafaelsteil Exp $
*/
public class ImageUtils
{
public static final int IMAGE_UNKNOWN = -1;
public static final int IMAGE_JPEG = 0;
public static final int IMAGE_PNG = 1;
public static final int IMAGE_GIF = 2;
/**
* Resizes an image
*
* @param imgName The image name to resize. Must be the complet path to the file
* @param type int
* @param maxWidth The image"s max width
* @param maxHeight The image"s max height
* @return A resized <code>BufferedImage</code>
*/
public static BufferedImage resizeImage(String imgName, int type, int maxWidth, int maxHeight)
{
try {
return resizeImage(ImageIO.read(new File(imgName)), type, maxWidth, maxHeight);
}
catch (IOException e) {
e.printStackTrace();
}
}
/**
* Resizes an image.
*
* @param image
* The image to resize
* @param maxWidth
* The image"s max width
* @param maxHeight
* The image"s max height
* @return A resized <code>BufferedImage</code>
* @param type
* int
*/
public static BufferedImage resizeImage(BufferedImage image, int type, int maxWidth, int maxHeight)
{
Dimension largestDimension = new Dimension(maxWidth, maxHeight);
// Original size
int imageWidth = image.getWidth(null);
int imageHeight = image.getHeight(null);
float aspectRatio = (float) imageWidth / imageHeight;
if (imageWidth > maxWidth || imageHeight > maxHeight) {
if ((float) largestDimension.width / largestDimension.height > aspectRatio) {
largestDimension.width = (int) Math.ceil(largestDimension.height * aspectRatio);
}
else {
largestDimension.height = (int) Math.ceil(largestDimension.width / aspectRatio);
}
imageWidth = largestDimension.width;
imageHeight = largestDimension.height;
}
return createHeadlessSmoothBufferedImage(image, type, imageWidth, imageHeight);
}
/**
* Saves an image to the disk.
*
* @param image The image to save
* @param toFileName The filename to use
* @param type The image type. Use <code>ImageUtils.IMAGE_JPEG</code> to save as JPEG images,
* or <code>ImageUtils.IMAGE_PNG</code> to save as PNG.
* @return <code>false</code> if no appropriate writer is found
*/
public static boolean saveImage(BufferedImage image, String toFileName, int type)
{
try {
return ImageIO.write(image, type == IMAGE_JPEG ? "jpg" : "png", new File(toFileName));
}
catch (IOException e) {
e.printStackTrace();
}
}
/**
* Compress and save an image to the disk. Currently this method only supports JPEG images.
*
* @param image The image to save
* @param toFileName The filename to use
* @param type The image type. Use <code>ImageUtils.IMAGE_JPEG</code> to save as JPEG images,
* or <code>ImageUtils.IMAGE_PNG</code> to save as PNG.
*/
public static void saveCompressedImage(BufferedImage image, String toFileName, int type)
{
try {
if (type == IMAGE_PNG) {
throw new UnsupportedOperationException("PNG compression not implemented");
}
Iterator iter = ImageIO.getImageWritersByFormatName("jpg");
ImageWriter writer;
writer = (ImageWriter) iter.next();
ImageOutputStream ios = ImageIO.createImageOutputStream(new File(toFileName));
writer.setOutput(ios);
ImageWriteParam iwparam = new JPEGImageWriteParam(Locale.getDefault());
iwparam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwparam.setCompressionQuality(0.7F);
writer.write(null, new IIOImage(image, null, null), iwparam);
ios.flush();
writer.dispose();
ios.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
/**
* Creates a <code>BufferedImage</code> from an <code>Image</code>. This method can
* function on a completely headless system. This especially includes Linux and Unix systems
* that do not have the X11 libraries installed, which are required for the AWT subsystem to
* operate. This method uses nearest neighbor approximation, so it"s quite fast. Unfortunately,
* the result is nowhere near as nice looking as the createHeadlessSmoothBufferedImage method.
*
* @param image The image to convert
* @param w The desired image width
* @param h The desired image height
* @return The converted image
* @param type int
*/
public static BufferedImage createHeadlessBufferedImage(BufferedImage image, int type, int width, int height)
{
if (type == ImageUtils.IMAGE_PNG && hasAlpha(image)) {
type = BufferedImage.TYPE_INT_ARGB;
}
else {
type = BufferedImage.TYPE_INT_RGB;
}
BufferedImage bi = new BufferedImage(width, height, type);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
bi.setRGB(x, y, image.getRGB(x * image.getWidth() / width, y * image.getHeight() / height));
}
}
return bi;
}
/**
* Creates a <code>BufferedImage</code> from an <code>Image</code>. This method can
* function on a completely headless system. This especially includes Linux and Unix systems
* that do not have the X11 libraries installed, which are required for the AWT subsystem to
* operate. The resulting image will be smoothly scaled using bilinear filtering.
*
* @param source The image to convert
* @param w The desired image width
* @param h The desired image height
* @return The converted image
* @param type int
*/
public static BufferedImage createHeadlessSmoothBufferedImage(BufferedImage source, int type, int width, int height)
{
if (type == ImageUtils.IMAGE_PNG && hasAlpha(source)) {
type = BufferedImage.TYPE_INT_ARGB;
}
else {
type = BufferedImage.TYPE_INT_RGB;
}
BufferedImage dest = new BufferedImage(width, height, type);
int sourcex;
int sourcey;
double scalex = (double) width / source.getWidth();
double scaley = (double) height / source.getHeight();
int x1;
int y1;
double xdiff;
double ydiff;
int rgb;
int rgb1;
int rgb2;
for (int y = 0; y < height; y++) {
sourcey = y * source.getHeight() / dest.getHeight();
ydiff = scale(y, scaley) - sourcey;
for (int x = 0; x < width; x++) {
sourcex = x * source.getWidth() / dest.getWidth();
xdiff = scale(x, scalex) - sourcex;
x1 = Math.min(source.getWidth() - 1, sourcex + 1);
y1 = Math.min(source.getHeight() - 1, sourcey + 1);
rgb1 = getRGBInterpolation(source.getRGB(sourcex, sourcey), source.getRGB(x1, sourcey), xdiff);
rgb2 = getRGBInterpolation(source.getRGB(sourcex, y1), source.getRGB(x1, y1), xdiff);
rgb = getRGBInterpolation(rgb1, rgb2, ydiff);
dest.setRGB(x, y, rgb);
}
}
return dest;
}
private static double scale(int point, double scale)
{
return point / scale;
}
private static int getRGBInterpolation(int value1, int value2, double distance)
{
int alpha1 = (value1 & 0xFF000000) >>> 24;
int red1 = (value1 & 0x00FF0000) >> 16;
int green1 = (value1 & 0x0000FF00) >> 8;
int blue1 = (value1 & 0x000000FF);
int alpha2 = (value2 & 0xFF000000) >>> 24;
int red2 = (value2 & 0x00FF0000) >> 16;
int green2 = (value2 & 0x0000FF00) >> 8;
int blue2 = (value2 & 0x000000FF);
int rgb = ((int) (alpha1 * (1.0 - distance) + alpha2 * distance) << 24)
| ((int) (red1 * (1.0 - distance) + red2 * distance) << 16)
| ((int) (green1 * (1.0 - distance) + green2 * distance) << 8)
| (int) (blue1 * (1.0 - distance) + blue2 * distance);
return rgb;
}
/**
* Determines if the image has transparent pixels.
*
* @param image The image to check for transparent pixel.s
* @return <code>true</code> of <code>false</code>, according to the result
*/
public static boolean hasAlpha(Image image)
{
try {
PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
pg.grabPixels();
return pg.getColorModel().hasAlpha();
}
catch (InterruptedException e) {
return false;
}
}
}
Creates and returns a buffered version of the specified image.
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
public class ImageUtil {
/**
* Creates and returns a buffered version of the specified image.
*
* @param image the image to create a buffered image for
* @return a buffered image based on the specified image
*/
public static BufferedImage getBufferedImage(Image image) {
BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null),
BufferedImage.TYPE_INT_ARGB);
Graphics g = bufferedImage.getGraphics();
g.drawImage(image, 0, 0, null);
return bufferedImage;
}
}
Creating a BufferedImage from an Image object
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
public class Main {
public static void main(String[] argv) throws Exception {
Image img = new ImageIcon("test.png").getImage();
BufferedImage bufferedImage = new BufferedImage(img.getWidth(null), img.getHeight(null),
BufferedImage.TYPE_INT_RGB);
Graphics g = bufferedImage.createGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
ImageIO.write(bufferedImage, "png", new File("a.png"));
}
}
Display image after operation
/*
* Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.awt.ruponent;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.ByteLookupTable;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.awt.image.LookupOp;
import java.awt.image.RescaleOp;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JApplet;
import javax.swing.JComboBox;
import javax.swing.JFrame;
class ImageDrawingComponent extends Component {
static String descs[] = { "Simple Copy", "Scale Up", "Scale Down",
"Scale Up : Bicubic", "Convolve : LowPass", "Convolve : Sharpen",
"RescaleOp", "LookupOp", };
int opIndex;
private BufferedImage bi;
int w, h;
public static final float[] SHARPEN3x3 = { // sharpening filter kernel
0.f, -1.f, 0.f, -1.f, 5.f, -1.f, 0.f, -1.f, 0.f };
public static final float[] BLUR3x3 = { 0.1f, 0.1f, 0.1f, // low-pass filter
// kernel
0.1f, 0.2f, 0.1f, 0.1f, 0.1f, 0.1f };
public ImageDrawingComponent(URL imageSrc) {
try {
bi = ImageIO.read(imageSrc);
w = bi.getWidth(null);
h = bi.getHeight(null);
if (bi.getType() != BufferedImage.TYPE_INT_RGB) {
BufferedImage bi2 = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics big = bi2.getGraphics();
big.drawImage(bi, 0, 0, null);
bi = bi2;
}
} catch (IOException e) {
System.out.println("Image could not be read");
System.exit(1);
}
}
public Dimension getPreferredSize() {
return new Dimension(w, h);
}
static String[] getDescriptions() {
return descs;
}
void setOpIndex(int i) {
opIndex = i;
}
/*
* In this example the image is recalculated on the fly every time This makes
* sense where repaints are infrequent or will use a different filter/op from
* the last. In other cases it may make sense to "cache" the results of the
* operation so that unless "opIndex" changes, drawing is always a simple
* copy. In such a case create the cached image and directly apply the filter
* to it and retain the resulting image to be repainted. The resulting image
* if untouched and unchanged Java 2D may potentially use hardware features to
* accelerate the blit.
*/
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
switch (opIndex) {
case 0: /* copy */
g.drawImage(bi, 0, 0, null);
break;
case 1: /* scale up using coordinates */
g.drawImage(bi, 0, 0, w, h, /* dst rectangle */
0, 0, w / 2, h / 2, /* src area of image */
null);
break;
case 2: /* scale down using transform */
g2.drawImage(bi, AffineTransform.getScaleInstance(0.7, 0.7), null);
break;
case 3: /* scale up using transform Op and BICUBIC interpolation */
AffineTransform at = AffineTransform.getScaleInstance(1.5, 1.5);
AffineTransformOp aop = new AffineTransformOp(at,
AffineTransformOp.TYPE_BICUBIC);
g2.drawImage(bi, aop, 0, 0);
break;
case 4: /* low pass filter */
case 5: /* sharpen */
float[] data = (opIndex == 4) ? BLUR3x3 : SHARPEN3x3;
ConvolveOp cop = new ConvolveOp(new Kernel(3, 3, data),
ConvolveOp.EDGE_NO_OP, null);
g2.drawImage(bi, cop, 0, 0);
break;
case 6: /* rescale */
RescaleOp rop = new RescaleOp(1.1f, 20.0f, null);
g2.drawImage(bi, rop, 0, 0);
break;
case 7: /* lookup */
byte lut[] = new byte[256];
for (int j = 0; j < 256; j++) {
lut[j] = (byte) (256 - j);
}
ByteLookupTable blut = new ByteLookupTable(0, lut);
LookupOp lop = new LookupOp(blut, null);
g2.drawImage(bi, lop, 0, 0);
break;
default:
}
}
}
public class ImageDrawingApplet extends JApplet {
static String imageFileName = "bld.jpg";
private URL imageSrc;
public ImageDrawingApplet() {
}
public ImageDrawingApplet(URL imageSrc) {
this.imageSrc = imageSrc;
}
public void init() {
try {
imageSrc = new URL(getCodeBase(), imageFileName);
} catch (MalformedURLException e) {
}
buildUI();
}
public void buildUI() {
final ImageDrawingComponent id = new ImageDrawingComponent(imageSrc);
add("Center", id);
JComboBox choices = new JComboBox(id.getDescriptions());
choices.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JComboBox cb = (JComboBox) e.getSource();
id.setOpIndex(cb.getSelectedIndex());
id.repaint();
};
});
add("South", choices);
}
public static void main(String s[]) {
JFrame f = new JFrame("ImageDrawing");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
URL imageSrc = null;
try {
imageSrc = ((new File(imageFileName)).toURI()).toURL();
} catch (MalformedURLException e) {
}
ImageDrawingApplet id = new ImageDrawingApplet(imageSrc);
id.buildUI();
f.add("Center", id);
f.pack();
f.setVisible(true);
}
}
Get average of a set of images with WritableRaster
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
public class Main {
static BufferedImage average(BufferedImage[] images) {
BufferedImage average = new BufferedImage(images[0].getWidth(), images[0].getHeight(),
BufferedImage.TYPE_BYTE_GRAY);
WritableRaster raster = average.getRaster().createCompatibleWritableRaster();
for (int k = 0; k < images[0].getHeight(); ++k) {
for (int j = 0; j < images[0].getWidth(); ++j) {
float sum = 0.0f;
for (int i = 0; i < images.length; ++i) {
sum = sum + images[i].getRaster().getSample(j, k, 0);
}
raster.setSample(j, k, 0, Math.round(sum / images.length));
}
}
average.setData(raster);
return average;
}
}
Make Linear Buffered Image
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id: GraphicsUtil.java 603243 2007-12-11 13:49:04Z jeremias $ */
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ruponentSampleModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBufferShort;
import java.awt.image.DataBufferUShort;
import java.awt.image.DirectColorModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.WritableRaster;
/**
* Set of utility methods for Graphics.
* These generally bypass broken methods in Java2D or provide tweaked
* implementations.
*
* @author
* @version $Id: GraphicsUtil.java 603243 2007-12-11 13:49:04Z jeremias $
*/
public class GraphicsUtil {
public static AffineTransform IDENTITY = new AffineTransform();
/**
* Standard prebuilt Linear_sRGB color model with no alpha */
public static final ColorModel Linear_sRGB =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_LINEAR_RGB), 24,
0x00FF0000, 0x0000FF00,
0x000000FF, 0x0, false,
DataBuffer.TYPE_INT);
/**
* Standard prebuilt Linear_sRGB color model with premultiplied alpha.
*/
public static final ColorModel Linear_sRGB_Pre =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_LINEAR_RGB), 32,
0x00FF0000, 0x0000FF00,
0x000000FF, 0xFF000000, true,
DataBuffer.TYPE_INT);
/**
* Standard prebuilt Linear_sRGB color model with unpremultiplied alpha.
*/
public static final ColorModel Linear_sRGB_Unpre =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_LINEAR_RGB), 32,
0x00FF0000, 0x0000FF00,
0x000000FF, 0xFF000000, false,
DataBuffer.TYPE_INT);
/**
* Standard prebuilt sRGB color model with no alpha.
*/
public static final ColorModel sRGB =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_sRGB), 24,
0x00FF0000, 0x0000FF00,
0x000000FF, 0x0, false,
DataBuffer.TYPE_INT);
/**
* Standard prebuilt sRGB color model with premultiplied alpha.
*/
public static final ColorModel sRGB_Pre =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_sRGB), 32,
0x00FF0000, 0x0000FF00,
0x000000FF, 0xFF000000, true,
DataBuffer.TYPE_INT);
/**
* Standard prebuilt sRGB color model with unpremultiplied alpha.
*/
public static final ColorModel sRGB_Unpre =
new DirectColorModel(ColorSpace.getInstance
(ColorSpace.CS_sRGB), 32,
0x00FF0000, 0x0000FF00,
0x000000FF, 0xFF000000, false,
DataBuffer.TYPE_INT);
/**
* Method that returns either Linear_sRGB_Pre or Linear_sRGB_UnPre
* based on premult flag.
* @param premult True if the ColorModel should have premultiplied alpha.
* @return a ColorMdoel with Linear sRGB colorSpace and
* the alpha channel set in accordance with
* <tt>premult</tt>
*/
public static ColorModel makeLinear_sRGBCM(boolean premult) {
return premult ? Linear_sRGB_Pre : Linear_sRGB_Unpre;
}
/**
* Constructs a BufferedImage with a linear sRGB colorModel, and alpha.
* @param width The desired width of the BufferedImage
* @param height The desired height of the BufferedImage
* @param premult The desired state of alpha premultiplied
* @return The requested BufferedImage.
*/
public static BufferedImage makeLinearBufferedImage(int width,
int height,
boolean premult) {
ColorModel cm = makeLinear_sRGBCM(premult);
WritableRaster wr = cm.createCompatibleWritableRaster(width, height);
return new BufferedImage(cm, wr, premult, null);
}
/**
* Coerces <tt>ras</tt> to be writable. The returned Raster continues to
* reference the DataBuffer from ras, so modifications to the returned
* WritableRaster will be seen in ras.<p>
*
* This method should only be used if you need a WritableRaster due to
* an interface (such as to construct a BufferedImage), but have no
* intention of modifying the contents of the returned Raster. If
* you have any doubt about other users of the data in <tt>ras</tt>,
* use copyRaster (above).
* @param ras The raster to make writable.
* @return A Writable version of ras (shares DataBuffer with
* <tt>ras</tt>).
*/
public static WritableRaster makeRasterWritable(Raster ras) {
return makeRasterWritable(ras, ras.getMinX(), ras.getMinY());
}
/**
* Coerces <tt>ras</tt> to be writable. The returned Raster continues to
* reference the DataBuffer from ras, so modifications to the returned
* WritableRaster will be seen in ras.<p>
*
* You can specify a new location for the returned WritableRaster, this
* is especially useful for constructing BufferedImages which require
* the Raster to be at (0,0).
*
* This method should only be used if you need a WritableRaster due to
* an interface (such as to construct a BufferedImage), but have no
* intention of modifying the contents of the returned Raster. If
* you have any doubt about other users of the data in <tt>ras</tt>,
* use copyRaster (above).
*
* @param ras The raster to make writable.
*
* @param minX The x location for the upper left corner of the
* returned WritableRaster.
*
* @param minY The y location for the upper left corner of the
* returned WritableRaster.
*
* @return A Writable version of <tT>ras</tt> with it"s upper left
* hand coordinate set to minX, minY (shares it"s DataBuffer
* with <tt>ras</tt>).
*/
public static WritableRaster makeRasterWritable(Raster ras,
int minX, int minY) {
WritableRaster ret = Raster.createWritableRaster
(ras.getSampleModel(),
ras.getDataBuffer(),
new Point(0,0));
ret = ret.createWritableChild
(ras.getMinX()-ras.getSampleModelTranslateX(),
ras.getMinY()-ras.getSampleModelTranslateY(),
ras.getWidth(), ras.getHeight(),
minX, minY, null);
return ret;
}
/**
* Create a new ColorModel with it"s alpha premultiplied state matching
* newAlphaPreMult.
* @param cm The ColorModel to change the alpha premult state of.
* @param newAlphaPreMult The new state of alpha premult.
* @return A new colorModel that has isAlphaPremultiplied()
* equal to newAlphaPreMult.
*/
public static ColorModel
coerceColorModel(ColorModel cm, boolean newAlphaPreMult) {
if (cm.isAlphaPremultiplied() == newAlphaPreMult)
return cm;
// Easiest way to build proper colormodel for new Alpha state...
// Eventually this should switch on known ColorModel types and
// only fall back on this hack when the CM type is unknown.
WritableRaster wr = cm.createCompatibleWritableRaster(1,1);
return cm.coerceData(wr, newAlphaPreMult);
}
/**
* Coerces data within a bufferedImage to match newAlphaPreMult,
* Note that this can not change the colormodel of bi so you
*
* @param wr The raster to change the state of.
* @param cm The colormodel currently associated with data in wr.
* @param newAlphaPreMult The desired state of alpha Premult for raster.
* @return A new colormodel that matches newAlphaPreMult.
*/
public static ColorModel
coerceData(WritableRaster wr, ColorModel cm, boolean newAlphaPreMult) {
// System.out.println("CoerceData: " + cm.isAlphaPremultiplied() +
// " Out: " + newAlphaPreMult);
if (!cm.hasAlpha())
// Nothing to do no alpha channel
return cm;
if (cm.isAlphaPremultiplied() == newAlphaPreMult)
// nothing to do alpha state matches...
return cm;
// System.out.println("CoerceData: " + wr.getSampleModel());
if (newAlphaPreMult) {
multiplyAlpha(wr);
} else {
divideAlpha(wr);
}
return coerceColorModel(cm, newAlphaPreMult);
}
public static void multiplyAlpha(WritableRaster wr) {
if (is_BYTE_COMP_Data(wr.getSampleModel()))
mult_BYTE_COMP_Data(wr);
else if (is_INT_PACK_Data(wr.getSampleModel(), true))
mult_INT_PACK_Data(wr);
else {
int [] pixel = null;
int bands = wr.getNumBands();
float norm = 1f/255f;
int x0, x1, y0, y1, a, b;
float alpha;
x0 = wr.getMinX();
x1 = x0+wr.getWidth();
y0 = wr.getMinY();
y1 = y0+wr.getHeight();
for (int y=y0; y<y1; y++)
for (int x=x0; x<x1; x++) {
pixel = wr.getPixel(x,y,pixel);
a = pixel[bands-1];
if ((a >= 0) && (a < 255)) {
alpha = a*norm;
for (b=0; b<bands-1; b++)
pixel[b] = (int)(pixel[b]*alpha+0.5f);
wr.setPixel(x,y,pixel);
}
}
}
}
public static void divideAlpha(WritableRaster wr) {
if (is_BYTE_COMP_Data(wr.getSampleModel()))
divide_BYTE_COMP_Data(wr);
else if (is_INT_PACK_Data(wr.getSampleModel(), true))
divide_INT_PACK_Data(wr);
else {
int x0, x1, y0, y1, a, b;
float ialpha;
int bands = wr.getNumBands();
int [] pixel = null;
x0 = wr.getMinX();
x1 = x0+wr.getWidth();
y0 = wr.getMinY();
y1 = y0+wr.getHeight();
for (int y=y0; y<y1; y++)
for (int x=x0; x<x1; x++) {
pixel = wr.getPixel(x,y,pixel);
a = pixel[bands-1];
if ((a > 0) && (a < 255)) {
ialpha = 255/(float)a;
for (b=0; b<bands-1; b++)
pixel[b] = (int)(pixel[b]*ialpha+0.5f);
wr.setPixel(x,y,pixel);
}
}
}
}
public static void copyBand(Raster src, int srcBand,
WritableRaster dst, int dstBand) {
Rectangle sR = src.getBounds();
Rectangle dR = dst.getBounds();
Rectangle cpR = sR.intersection(dR);
copyBand(src, cpR, srcBand, dst, cpR, dstBand);
}
public static void copyBand(Raster src, Rectangle sR, int sBand,
WritableRaster dst, Rectangle dR, int dBand) {
int dy = dR.y -sR.y;
int dx = dR.x -sR.x;
sR = sR.intersection(src.getBounds());
dR = dR.intersection(dst.getBounds());
int width, height;
if (dR.width < sR.width) width = dR.width;
else width = sR.width;
if (dR.height < sR.height) height = dR.height;
else height = sR.height;
int x = sR.x+dx;
int [] samples = null;
for (int y=sR.y; y< sR.y+height; y++) {
samples = src.getSamples(sR.x, y, width, 1, sBand, samples);
dst.setSamples(x, y+dy, width, 1, dBand, samples);
}
}
public static boolean is_INT_PACK_Data(SampleModel sm,
boolean requireAlpha) {
// Check ColorModel is of type DirectColorModel
if(!(sm instanceof SinglePixelPackedSampleModel)) return false;
// Check transfer type
if(sm.getDataType() != DataBuffer.TYPE_INT) return false;
SinglePixelPackedSampleModel sppsm;
sppsm = (SinglePixelPackedSampleModel)sm;
int [] masks = sppsm.getBitMasks();
if (masks.length == 3) {
if (requireAlpha) return false;
} else if (masks.length != 4)
return false;
if(masks[0] != 0x00ff0000) return false;
if(masks[1] != 0x0000ff00) return false;
if(masks[2] != 0x000000ff) return false;
if ((masks.length == 4) &&
(masks[3] != 0xff000000)) return false;
return true;
}
public static boolean is_BYTE_COMP_Data(SampleModel sm) {
// Check ColorModel is of type DirectColorModel
if(!(sm instanceof ComponentSampleModel)) return false;
// Check transfer type
if(sm.getDataType() != DataBuffer.TYPE_BYTE) return false;
return true;
}
protected static void divide_INT_PACK_Data(WritableRaster wr) {
// System.out.println("Divide Int");
SinglePixelPackedSampleModel sppsm;
sppsm = (SinglePixelPackedSampleModel)wr.getSampleModel();
final int width = wr.getWidth();
final int scanStride = sppsm.getScanlineStride();
DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
final int base
= (db.getOffset() +
sppsm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(),
wr.getMinY()-wr.getSampleModelTranslateY()));
// Access the pixel data array
final int[] pixels = db.getBankData()[0];
for (int y=0; y<wr.getHeight(); y++) {
int sp = base + y*scanStride;
final int end = sp + width;
while (sp < end) {
int pixel = pixels[sp];
int a = pixel>>>24;
if (a<=0) {
pixels[sp] = 0x00FFFFFF;
} else if (a<255) {
int aFP = (0x00FF0000/a);
pixels[sp] =
((a << 24) |
(((((pixel&0xFF0000)>>16)*aFP)&0xFF0000) ) |
(((((pixel&0x00FF00)>>8) *aFP)&0xFF0000)>>8 ) |
(((((pixel&0x0000FF)) *aFP)&0xFF0000)>>16));
}
sp++;
}
}
}
protected static void mult_INT_PACK_Data(WritableRaster wr) {
// System.out.println("Multiply Int: " + wr);
SinglePixelPackedSampleModel sppsm;
sppsm = (SinglePixelPackedSampleModel)wr.getSampleModel();
final int width = wr.getWidth();
final int scanStride = sppsm.getScanlineStride();
DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
final int base
= (db.getOffset() +
sppsm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(),
wr.getMinY()-wr.getSampleModelTranslateY()));
// Access the pixel data array
final int[] pixels = db.getBankData()[0];
for (int y=0; y<wr.getHeight(); y++) {
int sp = base + y*scanStride;
final int end = sp + width;
while (sp < end) {
int pixel = pixels[sp];
int a = pixel>>>24;
if ((a>=0) && (a<255)) { // this does NOT include a == 255 (0xff) !
pixels[sp] = ((a << 24) |
((((pixel&0xFF0000)*a)>>8)&0xFF0000) |
((((pixel&0x00FF00)*a)>>8)&0x00FF00) |
((((pixel&0x0000FF)*a)>>8)&0x0000FF));
}
sp++;
}
}
}
protected static void divide_BYTE_COMP_Data(WritableRaster wr) {
// System.out.println("Multiply Int: " + wr);
ComponentSampleModel csm;
csm = (ComponentSampleModel)wr.getSampleModel();
final int width = wr.getWidth();
final int scanStride = csm.getScanlineStride();
final int pixStride = csm.getPixelStride();
final int [] bandOff = csm.getBandOffsets();
DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
final int base
= (db.getOffset() +
csm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(),
wr.getMinY()-wr.getSampleModelTranslateY()));
int aOff = bandOff[bandOff.length-1];
int bands = bandOff.length-1;
// Access the pixel data array
final byte[] pixels = db.getBankData()[0];
for (int y=0; y<wr.getHeight(); y++) {
int sp = base + y*scanStride;
final int end = sp + width*pixStride;
while (sp < end) {
int a = pixels[sp+aOff]&0xFF;
if (a==0) {
for (int b = 0; b < bands; b++)
pixels[sp+bandOff[b]] = (byte)0xFF;
} else if (a<255) { // this does NOT include a == 255 (0xff) !
int aFP = (0x00FF0000/a);
for (int b = 0; b < bands; b++) {
int i = sp+bandOff[b];
pixels[i] = (byte)(((pixels[i]&0xFF)*aFP)>>>16);
}
}
sp+=pixStride;
}
}
}
protected static void mult_BYTE_COMP_Data(WritableRaster wr) {
// System.out.println("Multiply Int: " + wr);
ComponentSampleModel csm;
csm = (ComponentSampleModel)wr.getSampleModel();
final int width = wr.getWidth();
final int scanStride = csm.getScanlineStride();
final int pixStride = csm.getPixelStride();
final int [] bandOff = csm.getBandOffsets();
DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
final int base
= (db.getOffset() +
csm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(),
wr.getMinY()-wr.getSampleModelTranslateY()));
int aOff = bandOff[bandOff.length-1];
int bands = bandOff.length-1;
// Access the pixel data array
final byte[] pixels = db.getBankData()[0];
for (int y=0; y<wr.getHeight(); y++) {
int sp = base + y*scanStride;
final int end = sp + width*pixStride;
while (sp < end) {
int a = pixels[sp+aOff]&0xFF;
if (a!=0xFF)
for (int b = 0; b < bands; b++) {
int i = sp+bandOff[b];
pixels[i] = (byte)(((pixels[i]&0xFF)*a)>>8);
}
sp+=pixStride;
}
}
}
/*
This is skanky debugging code that might be useful in the future:
if (count == 33) {
String label = "sub [" + x + ", " + y + "]: ";
org.ImageDisplay.showImage
(label, subBI);
org.ImageDisplay.printImage
(label, subBI,
new Rectangle(75-iR.x, 90-iR.y, 32, 32));
}
// if ((count++ % 50) == 10)
// org.ImageDisplay.showImage("foo: ", subBI);
Graphics2D realG2D = g2d;
while (realG2D instanceof sun.java2d.ProxyGraphics2D) {
realG2D = ((sun.java2d.ProxyGraphics2D)realG2D).getDelegate();
}
if (realG2D instanceof sun.awt.image.BufferedImageGraphics2D) {
count++;
if (count == 34) {
RenderedImage ri;
ri = ((sun.awt.image.BufferedImageGraphics2D)realG2D).bufImg;
// g2d.setComposite(SVGComposite.OVER);
// org.ImageDisplay.showImage("Bar: " + count, cr);
org.ImageDisplay.printImage("Bar: " + count, cr,
new Rectangle(75, 90, 32, 32));
org.ImageDisplay.showImage ("Foo: " + count, ri);
org.ImageDisplay.printImage("Foo: " + count, ri,
new Rectangle(75, 90, 32, 32));
System.out.println("BI: " + ri);
System.out.println("BISM: " + ri.getSampleModel());
System.out.println("BICM: " + ri.getColorModel());
System.out.println("BICM class: " + ri.getColorModel().getClass());
System.out.println("BICS: " + ri.getColorModel().getColorSpace());
System.out.println
("sRGB CS: " +
ColorSpace.getInstance(ColorSpace.CS_sRGB));
System.out.println("G2D info");
System.out.println("\tComposite: " + g2d.getComposite());
System.out.println("\tTransform" + g2d.getTransform());
java.awt.RenderingHints rh = g2d.getRenderingHints();
java.util.Set keys = rh.keySet();
java.util.Iterator iter = keys.iterator();
while (iter.hasNext()) {
Object o = iter.next();
System.out.println("\t" + o.toString() + " -> " +
rh.get(o).toString());
}
ri = cr;
System.out.println("RI: " + ri);
System.out.println("RISM: " + ri.getSampleModel());
System.out.println("RICM: " + ri.getColorModel());
System.out.println("RICM class: " + ri.getColorModel().getClass());
System.out.println("RICS: " + ri.getColorModel().getColorSpace());
}
}
*/
/**
* Extracts an alpha raster from a RenderedImage. The method tries to avoid copying data
* unnecessarily by checking if the RenderedImage is a BufferedImage which offers suitable
* direct methods.
* @param image the image
* @return the alpha raster
*/
public static Raster getAlphaRaster(RenderedImage image) {
ColorModel cm = image.getColorModel();
if (!cm.hasAlpha() || cm.getTransparency() != ColorModel.TRANSLUCENT) {
throw new IllegalStateException("Image doesn"t have an alpha channel");
}
Raster alpha;
if (image instanceof BufferedImage) {
//Optimization possible with BufferedImage (No copying)
alpha = ((BufferedImage)image).getAlphaRaster();
} else {
WritableRaster wraster = GraphicsUtil.makeRasterWritable(image.getData());
alpha = image.getColorModel().getAlphaRaster(wraster);
}
return alpha;
}
}
Renders an ellipse overlapping a rectangle with the compositing rule and alpha value selected by the user
/*
* Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.JApplet;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/*
* This applet renders an ellipse overlapping a rectangle with the compositing
* rule and alpha value selected by the user.
*/
public class Composite extends JApplet implements ItemListener {
CompPanel comp;
JLabel alphaLabel, rulesLabel;
JComboBox alphas, rules;
String alpha = "1.0";
int rule = 0;
// Initializes the layout of the components.
public void init() {
GridBagLayout layOut = new GridBagLayout();
getContentPane().setLayout(layOut);
GridBagConstraints l = new GridBagConstraints();
l.weightx = 1.0;
l.fill = GridBagConstraints.BOTH;
l.gridwidth = GridBagConstraints.RELATIVE;
alphaLabel = new JLabel();
alphaLabel.setText("Alphas");
Font newFont = getFont().deriveFont(1);
alphaLabel.setFont(newFont);
alphaLabel.setHorizontalAlignment(JLabel.CENTER);
layOut.setConstraints(alphaLabel, l);
getContentPane().add(alphaLabel);
GridBagConstraints c = new GridBagConstraints();
getContentPane().setLayout(layOut);
l.gridwidth = GridBagConstraints.REMAINDER;
rulesLabel = new JLabel();
rulesLabel.setText("Rules");
newFont = getFont().deriveFont(1);
rulesLabel.setFont(newFont);
rulesLabel.setHorizontalAlignment(JLabel.CENTER);
layOut.setConstraints(rulesLabel, l);
getContentPane().add(rulesLabel);
GridBagConstraints a = new GridBagConstraints();
a.gridwidth = GridBagConstraints.RELATIVE;
a.weightx = 1.0;
a.fill = GridBagConstraints.BOTH;
alphas = new JComboBox();
layOut.setConstraints(alphas, a);
alphas.addItem("1.0");
alphas.addItem("0.75");
alphas.addItem("0.50");
alphas.addItem("0.25");
alphas.addItem("0.0");
alphas.addItemListener(this);
getContentPane().add(alphas);
a.gridwidth = GridBagConstraints.REMAINDER;
rules = new JComboBox();
layOut.setConstraints(rules, a);
rules.addItem("SRC");
rules.addItem("DST_IN");
rules.addItem("DST_OUT");
rules.addItem("DST_OVER");
rules.addItem("SRC_IN");
rules.addItem("SRC_OVER");
rules.addItem("SRC_OUT");
rules.addItem("CLEAR");
rules.addItemListener(this);
getContentPane().add(rules);
GridBagConstraints fC = new GridBagConstraints();
fC.fill = GridBagConstraints.BOTH;
fC.weightx = 1.0;
fC.weighty = 1.0;
fC.gridwidth = GridBagConstraints.REMAINDER;
comp = new CompPanel();
layOut.setConstraints(comp, fC);
getContentPane().add(comp);
validate();
}
/*
* Detects a change in either of the Choice components. Resets the variable
* corresponding to the Choice whose state is changed. Invokes changeRule in
* CompPanel with the current alpha and composite rules.
*/
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() != ItemEvent.SELECTED) {
return;
}
Object choice = e.getSource();
if (choice == alphas) {
alpha = (String) alphas.getSelectedItem();
} else {
rule = rules.getSelectedIndex();
}
comp.changeRule(alpha, rule);
}
public static void main(String s[]) {
JFrame f = new JFrame("Composite");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
JApplet applet = new Composite();
f.getContentPane().add("Center", applet);
applet.init();
f.pack();
f.setSize(new Dimension(300, 300));
f.setVisible(true);
}
}
class CompPanel extends JPanel {
AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC);
float alpha = 1.0f;
public CompPanel() {
}
// Resets the alpha and composite rules with selected items.
public void changeRule(String a, int rule) {
alpha = Float.valueOf(a).floatValue();
ac = AlphaComposite.getInstance(getRule(rule), alpha);
repaint();
}
// Gets the requested compositing rule.
public int getRule(int rule) {
int alphaComp = 0;
switch (rule) {
case 0:
alphaComp = AlphaComposite.SRC;
break;
case 1:
alphaComp = AlphaComposite.DST_IN;
break;
case 2:
alphaComp = AlphaComposite.DST_OUT;
break;
case 3:
alphaComp = AlphaComposite.DST_OVER;
break;
case 4:
alphaComp = AlphaComposite.SRC_IN;
break;
case 5:
alphaComp = AlphaComposite.SRC_OVER;
break;
case 6:
alphaComp = AlphaComposite.SRC_OUT;
break;
case 7:
alphaComp = AlphaComposite.CLEAR;
break;
}
return alphaComp;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Dimension d = getSize();
int w = d.width;
int h = d.height;
// Creates the buffered image.
BufferedImage buffImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D gbi = buffImg.createGraphics();
// Clears the previously drawn image.
g2.setColor(Color.white);
g2.fillRect(0, 0, d.width, d.height);
int rectx = w / 4;
int recty = h / 4;
// Draws the rectangle and ellipse into the buffered image.
gbi.setColor(new Color(0.0f, 0.0f, 1.0f, 1.0f));
gbi.fill(new Rectangle2D.Double(rectx, recty, 150, 100));
gbi.setColor(new Color(1.0f, 0.0f, 0.0f, 1.0f));
gbi.setComposite(ac);
gbi.fill(new Ellipse2D.Double(rectx + rectx / 2, recty + recty / 2, 150,
100));
// Draws the buffered image.
g2.drawImage(buffImg, null, 0, 0);
}
}
Renders multiple paragraphs of text in an array to an image (created and returned).
/*
*
* Created on March 16, 2007, 4:34 PM
*
* Copyright 2006-2007 Nigel Hughes
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at http://www.apache.org/
* licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.image.BufferedImage;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.util.Hashtable;
import java.util.LinkedList;
/**
* @author nigel
*/
public class Utils {
/**
* Renders multiple paragraphs of text in an array to an image (created and returned).
*
* @param font The font to use
* @param textColor The color of the text
* @param text The message in an array of strings (one paragraph in each
* @param width The width the text should be limited to
* @return An image with the text rendered into it
*/
public static BufferedImage renderTextToImage(Font font, Color textColor, String text[], int width){
LinkedList<BufferedImage> images = new LinkedList<BufferedImage>();
int totalHeight = 0;
for (String paragraph : text){
BufferedImage paraImage = renderTextToImage(font,textColor,paragraph,width);
totalHeight+=paraImage.getHeight();
images.add(paraImage);
}
BufferedImage image = createCompatibleImage(width,totalHeight);
Graphics2D graphics = (Graphics2D) image.createGraphics();
int y=0;
for (BufferedImage paraImage : images){
graphics.drawImage(paraImage,0,y,null);
y+=paraImage.getHeight();
}
graphics.dispose();
return image;
}
/**
* Renders a paragraph of text (line breaks ignored) to an image (created and returned).
*
* @param font The font to use
* @param textColor The color of the text
* @param text The message
* @param width The width the text should be limited to
* @return An image with the text rendered into it
*/
public static BufferedImage renderTextToImage(Font font, Color textColor, String text, int width){
Hashtable map = new Hashtable();
map.put(TextAttribute.FONT, font);
AttributedString attributedString = new AttributedString(text,map);
AttributedCharacterIterator paragraph = attributedString.getIterator();
FontRenderContext frc = new FontRenderContext(null, false, false);
int paragraphStart = paragraph.getBeginIndex();
int paragraphEnd = paragraph.getEndIndex();
LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, frc);
float drawPosY=0;
//First time around, just determine the height
while (lineMeasurer.getPosition() < paragraphEnd) {
TextLayout layout = lineMeasurer.nextLayout(width);
// Move it down
drawPosY += layout.getAscent() + layout.getDescent() + layout.getLeading();
}
BufferedImage image = createCompatibleImage(width,(int) drawPosY);
Graphics2D graphics = (Graphics2D) image.getGraphics();
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
drawPosY=0;
lineMeasurer.setPosition(paragraphStart);
while (lineMeasurer.getPosition() < paragraphEnd) {
TextLayout layout = lineMeasurer.nextLayout(width);
// Move y-coordinate by the ascent of the layout.
drawPosY += layout.getAscent();
/* Compute pen x position. If the paragraph is
right-to-left, we want to align the TextLayouts
to the right edge of the panel.
*/
float drawPosX;
if (layout.isLeftToRight()) {
drawPosX = 0;
} else {
drawPosX = width - layout.getAdvance();
}
// Draw the TextLayout at (drawPosX, drawPosY).
layout.draw(graphics, drawPosX, drawPosY);
// Move y-coordinate in preparation for next layout.
drawPosY += layout.getDescent() + layout.getLeading();
}
graphics.dispose();
return image;
}
/**
* Creates an image compatible with the current display
*
* @return A BufferedImage with the appropriate color model
*/
public static BufferedImage createCompatibleImage(int width, int height) {
GraphicsConfiguration configuration = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration();
return configuration.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
}
}
Save an image after operations
/*
* Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.awt.ruponent;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ByteLookupTable;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.awt.image.LookupOp;
import java.io.File;
import java.io.IOException;
import java.util.TreeSet;
import javax.imageio.ImageIO;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class SaveImage extends Component implements ActionListener {
String descs[] = { "Original", "Convolve : LowPass", "Convolve : Sharpen",
"LookupOp", };
int opIndex;
private BufferedImage bi, biFiltered;
int w, h;
public static final float[] SHARPEN3x3 = { // sharpening filter kernel
0.f, -1.f, 0.f, -1.f, 5.f, -1.f, 0.f, -1.f, 0.f };
public static final float[] BLUR3x3 = { 0.1f, 0.1f, 0.1f, // low-pass filter
// kernel
0.1f, 0.2f, 0.1f, 0.1f, 0.1f, 0.1f };
public SaveImage() {
try {
bi = ImageIO.read(new File("bld.jpg"));
w = bi.getWidth(null);
h = bi.getHeight(null);
if (bi.getType() != BufferedImage.TYPE_INT_RGB) {
BufferedImage bi2 = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics big = bi2.getGraphics();
big.drawImage(bi, 0, 0, null);
biFiltered = bi = bi2;
}
} catch (IOException e) {
System.out.println("Image could not be read");
System.exit(1);
}
}
public Dimension getPreferredSize() {
return new Dimension(w, h);
}
String[] getDescriptions() {
return descs;
}
void setOpIndex(int i) {
opIndex = i;
}
public void paint(Graphics g) {
filterImage();
g.drawImage(biFiltered, 0, 0, null);
}
int lastOp;
public void filterImage() {
BufferedImageOp op = null;
if (opIndex == lastOp) {
return;
}
lastOp = opIndex;
switch (opIndex) {
case 0:
biFiltered = bi; /* original */
return;
case 1: /* low pass filter */
case 2: /* sharpen */
float[] data = (opIndex == 1) ? BLUR3x3 : SHARPEN3x3;
op = new ConvolveOp(new Kernel(3, 3, data), ConvolveOp.EDGE_NO_OP, null);
break;
case 3: /* lookup */
byte lut[] = new byte[256];
for (int j = 0; j < 256; j++) {
lut[j] = (byte) (256 - j);
}
ByteLookupTable blut = new ByteLookupTable(0, lut);
op = new LookupOp(blut, null);
break;
}
/*
* Rather than directly drawing the filtered image to the destination,
* filter it into a new image first, then that filtered image is ready for
* writing out or painting.
*/
biFiltered = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
op.filter(bi, biFiltered);
}
/* Return the formats sorted alphabetically and in lower case */
public String[] getFormats() {
String[] formats = ImageIO.getWriterFormatNames();
TreeSet<String> formatSet = new TreeSet<String>();
for (String s : formats) {
formatSet.add(s.toLowerCase());
}
return formatSet.toArray(new String[0]);
}
public void actionPerformed(ActionEvent e) {
JComboBox cb = (JComboBox) e.getSource();
if (cb.getActionCommand().equals("SetFilter")) {
setOpIndex(cb.getSelectedIndex());
repaint();
} else if (cb.getActionCommand().equals("Formats")) {
/*
* Save the filtered image in the selected format. The selected item will
* be the name of the format to use
*/
String format = (String) cb.getSelectedItem();
/*
* Use the format name to initialise the file suffix. Format names
* typically correspond to suffixes
*/
File saveFile = new File("savedimage." + format);
JFileChooser chooser = new JFileChooser();
chooser.setSelectedFile(saveFile);
int rval = chooser.showSaveDialog(cb);
if (rval == JFileChooser.APPROVE_OPTION) {
saveFile = chooser.getSelectedFile();
/*
* Write the filtered image in the selected format, to the file chosen
* by the user.
*/
try {
ImageIO.write(biFiltered, format, saveFile);
} catch (IOException ex) {
}
}
}
};
public static void main(String s[]) {
JFrame f = new JFrame("Save Image Sample");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
SaveImage si = new SaveImage();
f.add("Center", si);
JComboBox choices = new JComboBox(si.getDescriptions());
choices.setActionCommand("SetFilter");
choices.addActionListener(si);
JComboBox formats = new JComboBox(si.getFormats());
formats.setActionCommand("Formats");
formats.addActionListener(si);
JPanel panel = new JPanel();
panel.add(choices);
panel.add(new JLabel("Save As"));
panel.add(formats);
f.add("South", panel);
f.pack();
f.setVisible(true);
}
}
Scale, convert images
// revised from richfaces photoalbum
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.zip.*;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageInputStream;
/**
* Utility class for operations with file-system
*
*/
public class FileUtils {
private static final String JPEG = "jpeg";
private static final String JPG = "jpg";
private static final int BUFFER_SIZE = 4 * 1024;
private static final boolean CLOCK = true;
private static final boolean VERIFY = true;
/**
* Utility method for copying file
* @param srcFile - source file
* @param destFile - destination file
*/
public static void copyFile(File srcFile, File destFile) throws IOException {
if (!srcFile.getPath().toLowerCase().endsWith(JPG) && !srcFile.getPath().toLowerCase().endsWith(JPEG)) {
return;
}
final InputStream in = new FileInputStream(srcFile);
final OutputStream out = new FileOutputStream(destFile);
try{
long millis = System.currentTimeMillis();
CRC32 checksum;
if (VERIFY) {
checksum = new CRC32();
checksum.reset();
}
final byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = in.read(buffer);
while (bytesRead >= 0) {
if (VERIFY) {
checksum.update(buffer, 0, bytesRead);
}
out.write(buffer, 0, bytesRead);
bytesRead = in.read(buffer);
}
if (CLOCK) {
millis = System.currentTimeMillis() - millis;
System.out.println("Copy file "" + srcFile.getPath() + "" on " + millis / 1000L + " second(s)");
}
}catch(IOException e){
throw e;
}finally{
out.close();
in.close();
}
}
/**
* Utility method for copying directory
* @param srcDir - source directory
* @param dstDir - destination directory
*/
public static void copyDirectory(File srcDir, File dstDir)
throws IOException {
if (".svn".equals(srcDir.getName())) {
return;
}
if (srcDir.isDirectory()) {
if (!dstDir.exists()) {
dstDir.mkdir();
}
for (String aChildren : srcDir.list()) {
copyDirectory(new File(srcDir, aChildren), new File(dstDir, aChildren));
}
} else {
copyFile(srcDir, dstDir);
}
}
/**
* Utility method for delete directory
* @param dir - directory to delete
* @param isInitialDelete - determine if the deleting process running at startup or on destroy of application
* @return true if directory succesfully deleted
*/
public static boolean deleteDirectory(File dir , boolean isInitialDelete){
if (dir.isDirectory()) {
if (dir.exists()) {
for (File child : dir.listFiles()) {
try{
deleteDirectory(child, isInitialDelete);
}catch(Exception e){
if(isInitialDelete){
continue;
}
else return false;
}
}
}
} else {
if (dir.exists()) {
final boolean isFileDeleted = dir.delete();
System.out.println((isFileDeleted ? "OK " : "ERROR ") +
"Delete file "" + dir.getPath() + "\"");
}
}
dir.delete();
return true;
}
/**
* Utility method for concatenation names of collection of files
* @param files - array of strings to concatenate
* @return concatenated string
*/
public static String joinFiles(String... files) {
final StringBuilder res = new StringBuilder();
for (String file : files) {
res.append(file).append(File.separatorChar);
}
return res.substring(0, res.length() - 1);
}
/**
* Utility method for delete file
* @param file - file to delete
*/
public static void deleteFile(File file) {
if (file.exists()) {
file.delete();
}
}
/**
* Utility method to read image from disk and transform image to BufferedImage object
* @param data - relative path to the image
* @param format - file prefix of the image
* @return BufferedImage representation of the image
*
*/
public static BufferedImage bitmapToImage(String data, String format) throws IOException {
final InputStream inb = new FileInputStream(data);
final ImageReader rdr = ImageIO.getImageReadersByFormatName(format).next();
final ImageInputStream imageInput = ImageIO.createImageInputStream(inb);
rdr.setInput(imageInput);
final BufferedImage image = rdr.read(0);
inb.close();
return image;
}
/**
* Utility method to write BufferedImage object to disk
* @param image - BufferedImage object to save.
* @param data - relative path to the image
* @param format - file prefix of the image
* @return BufferedImage representation of the image
*
*/
public static void imageToBitmap(BufferedImage image, String data, String format) throws IOException {
final OutputStream inb = new FileOutputStream(data);
final ImageWriter wrt = ImageIO.getImageWritersByFormatName(format).next();
final ImageInputStream imageInput = ImageIO.createImageOutputStream(inb);
wrt.setOutput(imageInput);
wrt.write(image);
inb.close();
}
/**
* Convenience method that returns a scaled instance of the
* provided {@code BufferedImage}.
*
* @param img the original image to be scaled
* @param targetWidth the desired width of the scaled instance,
* in pixels
* @param targetHeight the desired height of the scaled instance,
* in pixels
* @param hint one of the rendering hints that corresponds to
* {@code RenderingHints.KEY_INTERPOLATION} (e.g.
* {@code RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR},
* {@code RenderingHints.VALUE_INTERPOLATION_BILINEAR},
* {@code RenderingHints.VALUE_INTERPOLATION_BICUBIC})
* @param higherQuality if true, this method will use a multi-step
* scaling technique that provides higher quality than the usual
* one-step technique (only useful in downscaling cases, where
* {@code targetWidth} or {@code targetHeight} is
* smaller than the original dimensions, and generally only when
* the {@code BILINEAR} hint is specified)
* @return a scaled version of the original {@code BufferedImage}
*/
public static BufferedImage getScaledInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality) {
final int type = img.getTransparency() == Transparency.OPAQUE ?
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
int w;
int h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
final BufferedImage tmp = new BufferedImage(w, h, type);
final Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
return ret;
}
/**
* Utility method for creation of directory
* @param directory - directory to create
*
*/
public static void addDirectory(File directory) {
if (directory.exists()) {
deleteDirectory(directory, false);
}
directory.mkdirs();
}
}
Sharpening a Buffered Image
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
public class Main {
public static void main(String[] argv) throws Exception {
BufferedImage bufferedImage = new BufferedImage(200, 200,
BufferedImage.TYPE_BYTE_INDEXED);
Kernel kernel = new Kernel(3, 3, new float[] { -1, -1, -1, -1, 9, -1, -1,
-1, -1 });
BufferedImageOp op = new ConvolveOp(kernel);
bufferedImage = op.filter(bufferedImage, null);
}
}