I am attempting to calculate the pixel height of a rotated string in Java. At the moment, I am creating an affine transformation and rotating it by the desired amount.
Then, I create a font derived form this affine transformation. I also create a FontRenderContect and a GlyphVector.
When I attempt to get the pixel bounds from the glyph vector, it gives me the height of the text as if it weren't rotated
AffineTransform affineTransform = new AffineTransform();
affineTransform.rotate(Math.toRadians(45),0,0);
Font rotatedFont = font.deriveFont(affineTransform);
FontRenderContext frc = new FontRenderContext(affineTransform, true, false);
GlyphVector gv = rotatedFont.createGlyphVector(frc, "i");
System.out.println(gv.getPixelBounds(frc, 0, 0).getBounds());
gv = rotatedFont.createGlyphVector(frc, "iiiiiiiiiiii");
System.out.println(gv.getPixelBounds(frc, 0, 0).getBounds());
Results in:
java.awt.Rectangle[x=0,y=1,width=9,height=2]
java.awt.Rectangle[x=0,y=1,width=31,height=2]
The height should be much greater as it is rotated at a 45 degree angle (the width should equal the height).
Any help is appreciated.
Determining the bounding box is made easy by using a Shape & applying the AffineTransform directly to that shape.
import java.awt.*;
import java.awt.geom.*;
import java.awt.font.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class BoundingBoxRotatedText {
private JComponent ui = null;
JLabel output = new JLabel();
Font font = new Font(Font.SERIF, Font.PLAIN, 20);
String string = "The quick brown fox jumps over the lazy dog";
Shape textShape = getShapeOfText(font, string);
Rectangle2D rectangle = textShape.getBounds2D();
BoundingBoxRotatedText() {
initUI();
}
public final void initUI() {
if (ui!=null) return;
ui = new JPanel(new BorderLayout(4,4));
ui.setBorder(new EmptyBorder(4,4,4,4));
ui.add(output);
output.setIcon(new ImageIcon(getImage()));
}
public static Shape getShapeOfText(Font font, String msg) {
BufferedImage bi = new BufferedImage(
1, 1, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
FontRenderContext frc = g.getFontRenderContext();
GlyphVector gv = font.createGlyphVector(frc, msg);
return gv.getOutline();
}
public static Shape moveShapeToCenter(Shape shape, int w, int h) {
Rectangle2D b = shape.getBounds2D();
double xOff = -b.getX() + ((w - b.getWidth()) / 2d);
double yOff = -b.getY() + ((h - b.getHeight()) / 2d);
AffineTransform move = AffineTransform.getTranslateInstance(xOff, yOff);
return move.createTransformedShape(shape);
}
private BufferedImage getImage() {
int sz = (int)(rectangle.getBounds().width*1.2);
BufferedImage bi = new BufferedImage(
sz, sz, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, sz, sz);
Shape shape = moveShapeToCenter(textShape, sz, sz);
g.setColor(Color.GREEN);
g.fill(shape);
g.draw(shape);
g.draw(shape.getBounds());
AffineTransform rotate45 = AffineTransform.
getRotateInstance(Math.PI/4, sz/2, sz/2);
shape = rotate45.createTransformedShape(shape);
g.setColor(Color.BLUE);
g.fill(shape);
g.draw(shape);
g.draw(shape.getBounds());
shape = rotate45.createTransformedShape(shape);
g.setColor(Color.RED);
g.fill(shape);
g.draw(shape);
g.draw(shape.getBounds());
g.dispose();
return bi;
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
ex.printStackTrace();
}
BoundingBoxRotatedText o = new BoundingBoxRotatedText();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}
Related
I am developing a navigation system in Java. The map should be drawn in the middle, with indicators on the left and right.
How do I make the map slowly fade out on both sides?
As shown above, the roads are drawn across the entire window via Graphics2D. How can I make a gradient with left and right transparent and center color x?
for(Street street : streets){
g2d.setColor(Color.BLACK);
if(street.distanceToCurrentPosition() * factor < width * 2){
Integer last_x = null;
Integer last_y = null;
street.setupGraphicSettings(g2d);
if(street.getType() != ""){
for(WayPoint wayPoint : street.getWayPoints()){
int waypoint_x = (int) (wayPoint.getDistanceLongitudeTo(current_position) * factor) + middle_x;
int waypoint_y = - (int) (wayPoint.getDistanceLatitudeTo(current_position) * (double) factor) + middle_y;
if(last_x != null || last_y != null){;
g2d.drawLine(waypoint_x, waypoint_y, last_x, last_y);
}
last_x = waypoint_x;
last_y = waypoint_y;
}
}
}else return;
A working code solution
The "basic" idea is to use a combination of LinearGradientPaint and AlphaComposite to apply an alpha based "mask" to the core map image - now, this assumes you have an image based map.
Start by taking a look at:
2D Graphics Trail
Stroking and Filling Graphics Primitives
Compositing Graphics
Basically, we create a alpha based "mask":
BufferedImage alphaMask = new BufferedImage(baseMap.getWidth(), baseMap.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = alphaMask.createGraphics();
Color opaqueColor = new Color(0, 0, 0, 255);
Color alphaColor = new Color(0, 0, 0, 0);
LinearGradientPaint lgp = new LinearGradientPaint(
new Point(0, 0),
new Point(baseMap.getWidth(), 0),
new float[]{0f, 0.1f, 0.25f, 0.75f, 0.9f, 1f},
new Color[]{alphaColor, alphaColor, opaqueColor, opaqueColor, alphaColor, alphaColor}
);
g2d.setPaint(lgp);
g2d.fillRect(0, 0, alphaMask.getWidth(), alphaMask.getHeight());
g2d.dispose();
Note, we're not really interested in the color, just there alpha values.
Next, we use a AlphaComposite.DST_IN to "mask" the source image, this done via a utility method...
public static BufferedImage applyMask(BufferedImage sourceImage, BufferedImage maskImage, int method) {
BufferedImage maskedImage = null;
if (sourceImage != null) {
int width = maskImage.getWidth();
int height = maskImage.getHeight();
maskedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D mg = maskedImage.createGraphics();
int x = (width - sourceImage.getWidth()) / 2;
int y = (height - sourceImage.getHeight()) / 2;
mg.drawImage(sourceImage, x, y, null);
mg.setComposite(AlphaComposite.getInstance(method));
mg.drawImage(maskImage, 0, 0, null);
mg.dispose();
}
return maskedImage;
}
Runnable example
NB: The component's background is set to red to demonstrate the alpha masking
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
try {
frame.add(new TestPane());
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage maskedMap;
public TestPane() throws IOException {
BufferedImage baseMap = ImageIO.read(getClass().getResource("/images/MiddleEarth.jpeg"));
BufferedImage alphaMask = new BufferedImage(baseMap.getWidth(), baseMap.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = alphaMask.createGraphics();
Color opaqueColor = new Color(0, 0, 0, 255);
Color alphaColor = new Color(0, 0, 0, 0);
LinearGradientPaint lgp = new LinearGradientPaint(
new Point(0, 0),
new Point(baseMap.getWidth(), 0),
new float[]{0f, 0.1f, 0.25f, 0.75f, 0.9f, 1f},
new Color[]{alphaColor, alphaColor, opaqueColor, opaqueColor, alphaColor, alphaColor}
);
g2d.setPaint(lgp);
g2d.fillRect(0, 0, alphaMask.getWidth(), alphaMask.getHeight());
g2d.dispose();
maskedMap = applyMask(baseMap, alphaMask, AlphaComposite.DST_IN);
// Just to prove the point
setBackground(Color.RED);
}
#Override
public Dimension getPreferredSize() {
return maskedMap == null ? new Dimension(200, 200) : new Dimension(maskedMap.getWidth(), maskedMap.getHeight());
}
public static BufferedImage applyMask(BufferedImage sourceImage, BufferedImage maskImage, int method) {
BufferedImage maskedImage = null;
if (sourceImage != null) {
int width = maskImage.getWidth();
int height = maskImage.getHeight();
maskedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D mg = maskedImage.createGraphics();
int x = (width - sourceImage.getWidth()) / 2;
int y = (height - sourceImage.getHeight()) / 2;
mg.drawImage(sourceImage, x, y, null);
mg.setComposite(AlphaComposite.getInstance(method));
mg.drawImage(maskImage, 0, 0, null);
mg.dispose();
}
return maskedImage;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON
);
g2d.setRenderingHints(hints);
int x = (getWidth() - maskedMap.getWidth()) / 2;
int y = (getHeight() - maskedMap.getHeight()) / 2;
g2d.drawImage(maskedMap, x, y, this);
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(3f));
// There's a nice and interesting effect ;)
g2d.setComposite(AlphaComposite.SrcOver.derive(0.9f));
int diameter = getWidth() / 4;
x = ((getWidth() / 2) - diameter) / 2;
y = (getHeight() - diameter) / 2;
g2d.fillOval(x, y, diameter, diameter);
x = getWidth() - (((getWidth() / 2) + diameter) / 2);
g2d.fillOval(x, y, diameter, diameter);
g2d.dispose();
}
}
}
I want to rotate a bufferedImage. The code I use makes it possible that the image rotates. But it cuts the image to a square. The screen shows then a black "border" on the left and the right side.
If I use debugging tool, the image width is about the whole width included the black "border". But the black "border" don't rotate, it's always at the left and the right side. And the image is missing the picture-parts left and right. The squared-image isn't cut again if I rotate it again. If I change the src.getWidth()-parts the image will be smaller with each rotation.
private static BufferedImage rotateImage(BufferedImage src, double degrees) {
AffineTransform affineTransform = AffineTransform.getRotateInstance(
Math.toRadians(degrees), (src.getWidth() / 2), (src.getHeight() / 2));
BufferedImage rotatedImage = new BufferedImage(src.getWidth(), src.getHeight(), src.getType());
Graphics2D g = (Graphics2D) rotatedImage.getGraphics();
g.setTransform(affineTransform);
g.drawImage(src, 0, 0, null);
return rotatedImage;
}
public void rotateImage(int degree) {
if (this.image != null) {
this.setImage(myJComponent.rotateImage(this.image, degree));
}
}
The size of the image will change as you rotate it.
Here is some code to play with:
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;
public class Rotation
{
BufferedImage image;
JLabel label;
public Rotation(BufferedImage image)
{
this.image = image;
}
private BufferedImage getImage(double theta)
{
// Determine the size of the rotated image
double cos = Math.abs(Math.cos(theta));
double sin = Math.abs(Math.sin(theta));
double width = image.getWidth();
double height = image.getHeight();
int w = (int)(width * cos + height * sin);
int h = (int)(width * sin + height * cos);
// Rotate and paint the original image onto a BufferedImage
BufferedImage out = new BufferedImage(w, h, image.getType());
Graphics2D g2 = out.createGraphics();
g2.setPaint(UIManager.getColor("Panel.background"));
g2.fillRect(0,0,w,h);
double x = w/2;
double y = h/2;
AffineTransform at = AffineTransform.getRotateInstance(theta, x, y);
x = (w - width)/2;
y = (h - height)/2;
at.translate(x, y);
g2.drawRenderedImage(image, at);
g2.dispose();
return out;
}
private JLabel getLabel()
{
ImageIcon icon = new ImageIcon(image);
label = new JLabel(icon);
label.setHorizontalAlignment(JLabel.CENTER);
return label;
}
private JSlider getSlider()
{
final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
slider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
int value = slider.getValue();
BufferedImage bi = getImage(Math.toRadians(value));
label.setIcon(new ImageIcon(bi));
}
});
return slider;
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
String path = "mong.jpg";
ClassLoader cl = Rotation.class.getClassLoader();
BufferedImage bi = ImageIO.read(cl.getResourceAsStream(path));
Rotation r = new Rotation(bi);
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new JScrollPane(r.getLabel()));
f.getContentPane().add(r.getSlider(), "South");
f.pack();
f.setLocation(200,200);
f.setVisible(true);
}
catch(IOException e)
{
System.out.println(e);
}
}
});
}
}
Just change the image you want to read and use the slider to rotate the image.
I am rotating and scaling the image using AffineTransform. When I display the image using Graphics2D.drawImage() the whole image does not get displayed so I am calling the AffineTransform.translate method.
Here is the code I have currently written:
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Dimension dim = getPreferredSize();
int x = (getWidth() - image.getWidth(null)) / 2;
int y = (getHeight() - image.getHeight(null)) / 2;
double angle = Math.toRadians(rotateAngle);
AffineTransform identity = new AffineTransform();
identity.scale(scale, scale);
identity.translate(x,y);
AffineTransform at = new AffineTransform();
setPreferredSize(new Dimension((int)(identity.getTranslateX()+(image.getWidth(null)*scale)),(int)(identity.getTranslateY()+(image.getHeight(null)*scale))));
at.setTransform(identity);
at.rotate(angle);
g2d.transform(at);
g2d.drawImage(image, 0, 0, this);
g2d.dispose();
}
The translate method sometimes displays the whole image and sometimes does not depending on the image size and rotating angle. Is there anyway to make sure the whole image gets displayed after a rotate.
I had a look at this previous asked question:
Java2D Image Rotation Issue
but the solution posted there gave the same problem for me.
I finally figured out a way to do this for 90 degrees, it will not work for other degrees.
void rotate90(){
if(image!=null){
int w = image.getWidth(null); //the Width of the original image
int h = image.getHeight(null);//the Height of the original image
if(w>h){
BufferedImage dimg = new BufferedImage(w, w, BufferedImage.TYPE_3BYTE_BGR );
Graphics2D g = dimg.createGraphics();
g.translate(-(w-h), 0);
g.rotate(Math.toRadians(90), w/2, w/2);
g.drawImage(image, 0, 0,null);
BufferedImage bimg = new BufferedImage(h, w, BufferedImage.TYPE_3BYTE_BGR );
Graphics2D g2 = (Graphics2D)bimg.getGraphics();
g2.drawImage(dimg,0,0,h,w,0,0,h,w,null);
dimg.flush();
dimg=null;
image = createImage(bimg.getSource());
bimg.flush();
bimg= null;
}
else{
BufferedImage dimg = new BufferedImage(h, h, BufferedImage.TYPE_3BYTE_BGR );
Graphics2D g = dimg.createGraphics();
g.translate(-(w-h), 0);
g.rotate(Math.toRadians(90), w/2, w/2);
g.drawImage(image, 0, 0,null);
BufferedImage bimg = new BufferedImage(h, w, BufferedImage.TYPE_3BYTE_BGR );
Graphics2D g2 = (Graphics2D)bimg.getGraphics();
g2.drawImage(dimg,0,0,h,w,0,0,h,w,null);
dimg.flush();
dimg=null;
image = createImage(bimg.getSource());
bimg.flush();
bimg= null;
}
}
}
void rotateClockWise(){
if(image!=null){
rotate90();
setPanelsize();
revalidate();
repaint();
}
}
sometimes displays the whole image and sometimes does not depending on the image size and rotating angle
You need to recalculate the size of the rotated image. Here is an example of how to do that:
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;
public class Rotation
{
BufferedImage image;
JLabel label;
public Rotation(BufferedImage image)
{
this.image = image;
}
private BufferedImage getImage(double theta)
{
// Determine the size of the rotated image
double cos = Math.abs(Math.cos(theta));
double sin = Math.abs(Math.sin(theta));
double width = image.getWidth();
double height = image.getHeight();
int w = (int)(width * cos + height * sin);
int h = (int)(width * sin + height * cos);
// Rotate and paint the original image onto a BufferedImage
BufferedImage out = new BufferedImage(w, h, image.getType());
Graphics2D g2 = out.createGraphics();
g2.setPaint(UIManager.getColor("Panel.background"));
g2.fillRect(0,0,w,h);
double x = w/2;
double y = h/2;
AffineTransform at = AffineTransform.getRotateInstance(theta, x, y);
x = (w - width)/2;
y = (h - height)/2;
at.translate(x, y);
g2.drawRenderedImage(image, at);
g2.dispose();
return out;
}
private JLabel getLabel()
{
ImageIcon icon = new ImageIcon(image);
label = new JLabel(icon);
label.setHorizontalAlignment(JLabel.CENTER);
return label;
}
private JSlider getSlider()
{
final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
slider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
int value = slider.getValue();
BufferedImage bi = getImage(Math.toRadians(value));
label.setIcon(new ImageIcon(bi));
}
});
return slider;
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
String path = "mong.jpg";
ClassLoader cl = Rotation.class.getClassLoader();
BufferedImage bi = ImageIO.read(cl.getResourceAsStream(path));
Rotation r = new Rotation(bi);
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new JScrollPane(r.getLabel()));
f.getContentPane().add(r.getSlider(), "South");
f.pack();
f.setLocation(200,200);
f.setVisible(true);
}
catch(IOException e)
{
System.out.println(e);
}
}
});
}
}
Not sure how the scaling will affect this. Maybe you can just multiply the width/height by the scaling factor?
I convert an image to black&white in imagemagick with a command like this:
convert myimg.png -monochrome out3.png
I'm wondering whether its possible to achieve the same result in Java? Without using Im4Java or JMagick?
I guess it depends on what you mean by "mono-chrome"/"black & white"...
public class TestBlackAndWhite {
public static void main(String[] args) {
new TestBlackAndWhite();
}
public TestBlackAndWhite() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage master;
private BufferedImage grayScale;
private BufferedImage blackWhite;
public TestPane() {
try {
master = ImageIO.read(new File("C:/Users/shane/Dropbox/pictures/439px-Join!_It's_your_duty!.jpg"));
grayScale = ImageIO.read(new File("C:/Users/shane/Dropbox/pictures/439px-Join!_It's_your_duty!.jpg"));
ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
op.filter(grayScale, grayScale);
blackWhite = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
Graphics2D g2d = blackWhite.createGraphics();
g2d.drawImage(master, 0, 0, this);
g2d.dispose();
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
if (master != null) {
size = new Dimension(master.getWidth() * 3, master.getHeight());
}
return size;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (master != null) {
int x = (getWidth() - (master.getWidth() * 3)) / 2;
int y = (getHeight() - master.getHeight()) / 2;
g.drawImage(master, x, y, this);
x += master.getWidth();
g.drawImage(grayScale, x, y, this);
x += master.getWidth();
g.drawImage(blackWhite, x, y, this);
}
}
}
}
Try this crude example. We brighten or darken the image first using RescaleOp.
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
class ColorToBlackAndWhite {
/**
* Returns the supplied src image brightened by a float value from 0 to 10.
* Float values below 1.0f actually darken the source image.
*/
public static BufferedImage brighten(BufferedImage src, float level) {
BufferedImage dst = new BufferedImage(
src.getWidth(), src.getHeight(), BufferedImage.TYPE_INT_RGB);
float[] scales = {level, level, level};
float[] offsets = new float[4];
RescaleOp rop = new RescaleOp(scales, offsets, null);
Graphics2D g = dst.createGraphics();
g.drawImage(src, rop, 0, 0);
g.dispose();
return dst;
}
public static void main(String[] args) throws Exception {
URL colorURL = new URL("http://i.stack.imgur.com/AuY9o.png");
final BufferedImage colorImage = ImageIO.read(colorURL);
float[] scales = {2f, 2f, 2f};
float[] offsets = new float[4];
RescaleOp rop = new RescaleOp(scales, offsets, null);
final BufferedImage scaledImage = new BufferedImage(
colorImage.getWidth(),
colorImage.getHeight(),
BufferedImage.TYPE_INT_RGB);
Graphics2D g = scaledImage.createGraphics();
g.drawImage(colorImage, rop, 0, 0);
final BufferedImage grayImage = new BufferedImage(
colorImage.getWidth(),
colorImage.getHeight(),
BufferedImage.TYPE_BYTE_GRAY);
g = grayImage.createGraphics();
g.drawImage(colorImage, 0, 0, null);
final BufferedImage blackAndWhiteImage = new BufferedImage(
colorImage.getWidth(),
colorImage.getHeight(),
BufferedImage.TYPE_BYTE_BINARY);
g = blackAndWhiteImage.createGraphics();
g.drawImage(colorImage, 0, 0, null);
g.dispose();
Runnable r = new Runnable() {
#Override
public void run() {
JPanel gui = new JPanel(new BorderLayout(2, 2));
JPanel images = new JPanel(new GridLayout(0, 2, 2, 2));
gui.add(images, BorderLayout.CENTER);
final JLabel scaled = new JLabel(new ImageIcon(scaledImage));
final JSlider brighten = new JSlider(0, 1000, 100);
gui.add(brighten, BorderLayout.PAGE_START);
ChangeListener cl = new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
int val = brighten.getValue();
float valFloat = val / 1000f;
BufferedImage bi = brighten(colorImage, valFloat);
BufferedImage bw = new BufferedImage(
colorImage.getWidth(),
colorImage.getHeight(),
BufferedImage.TYPE_BYTE_BINARY);
Graphics g = bw.createGraphics();
g.drawImage(bi, 0, 0, null);
g.dispose();
scaled.setIcon(new ImageIcon(bw));
}
};
brighten.addChangeListener(cl);
images.add(new JLabel(new ImageIcon(colorImage)));
images.add(scaled);
images.add(new JLabel(new ImageIcon(grayImage)));
images.add(new JLabel(new ImageIcon(blackAndWhiteImage)));
JOptionPane.showMessageDialog(null, gui);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}
The effect you are achieving is not through a binarization by a pre-defined threshold, instead it is done by a technique called dithering. Many dithering methods works by propagation the error (the intensity in the present image - the binary output at a given point) and thus adjusting the next outputs. This is done to create a visual effect such that it might seem like the resulting image is not black & white -- if you don't look too closely at it.
One such simple and well-known method goes by Floyd-Steinberg, a pseudo-code for it is:
for y := 1 to image height
for x := 1 to image width
v := im(y, x)
if v < 128 then
result(y, x) := 0
else
result(y, x) := 255
error := v - result(y, x)
propagate_error(im, y, x, error)
Where propagate_error for this method can be given as (without taking care of border cases):
im(y, x+1) := im(y, x+1) + (7/16) * error
im(y+1, x+1) := im(y+1, x+1) + (1/16) * error
im(y+1, x ) := im(y+1, x ) + (5/16) * error
im(y+1, x-1) := im(y+1, x-1) + (3/16) * error
Considering the direct implementation of the pseudocode given, the following image at right is the binary version of the one at its left. There is in fact only black and white colors at the image at right, this is a trivial matter for those that know about this method but for those unaware this might seem like impossible. The patterns created give the impression that there are several gray tones, depending from far you look at the image.
-Try below simple code,
package com.bethecoder.tutorials.imageio;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class BlackAndWhiteTest {
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
File file = new File("C:/Temp/stpatricks_08.gif");
BufferedImage orginalImage = ImageIO.read(file);
BufferedImage blackAndWhiteImg = new BufferedImage(
orginalImage.getWidth(), orginalImage.getHeight(),
BufferedImage.TYPE_BYTE_BINARY);
Graphics2D graphics = blackAndWhiteImg.createGraphics();
graphics.drawImage(orginalImage, 0, 0, null);
ImageIO.write(blackAndWhiteImg, "png", new File("c:/Temp/stpatricks_08_bw.png"));
}
}
I am looking for the simplest way to draw some
text around an ellipse object on my app.
I need to create a feeling of "cuddling".
So far, I've used the Graphics2D class to print my drawings
on screen and my "canvas" is a BufferedImage.
The width and height of my ellipses are constant at 50,50 respectively.
Any suggestions?
Here's an example of curved text:
// slightly modified from the original:
// http://examples.oreilly.com/9781565924840/examples/RollingText.java
import javax.swing.*;
import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;
public class RollingText extends JFrame {
RollingText() {
super("RollingText v1.0");
super.setSize(650, 350);
super.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
String s = "What's our vector, Victor?";
Font font = new Font("Serif", Font.PLAIN, 24);
FontRenderContext frc = g2.getFontRenderContext();
g2.translate(40, 80);
GlyphVector gv = font.createGlyphVector(frc, s);
int length = gv.getNumGlyphs();
for (int i = 0; i < length; i++) {
Point2D p = gv.getGlyphPosition(i);
double theta = (double) i / (double) (length - 1) * Math.PI / 4;
AffineTransform at = AffineTransform.getTranslateInstance(p.getX(), p.getY());
at.rotate(theta);
Shape glyph = gv.getGlyphOutline(i);
Shape transformedGlyph = at.createTransformedShape(glyph);
g2.fill(transformedGlyph);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new RollingText().setVisible(true);
}
});
}
}
which produces: