Java Swing draw html formatted string - java

I want to create a String which displays the time in the format: 10h 30min, but the units (h and min) should have a smaller font than the numbers. When using a JLabel, I get this work with a html formatted string with span attributes.
Now I want to add such a String to a custom object and write it with the drawAlignedString method. But, here the html passing does not working. The custom object than shows my code and not the formatted String.
Is there a way to get this working or any other solution for drawing Strings with diffrent Substrings?
This is what I've tried:
String time = String.format(
"<html>%d<span style=\"font-family:Arial Unicode MS;font-size:12px;\">h </span> %d<span "
+ "style=\"font-family:Arial Unicode MS;font-size:12px;\">min</span></html>",
absSeconds / 3600, (absSeconds % 3600) / 60);
g2.setFont(this.centerTextFont);
g2.setPaint(this.centerTextColor);
TextUtilities.drawAlignedString(time, g2, (float) area.getCenterX(), (float) area.getCenterY(),
TextAnchor.CENTER);

Once the label is configured, pass the Graphics to the paint method of the label.
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class LabelRenderTest {
public static void main(String[] args) {
SwingUtilities.invokeLater( new Runnable() {
public void run() {
String title = "<html><body style='width: 200px; padding: 5px;'>"
+ "<h1>Do U C Me?</h1>"
+ "Here is a long string that will wrap. "
+ "The effect we want is a multi-line label.";
JFrame f = new JFrame("Label Render Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BufferedImage image = new BufferedImage(
400,
300,
BufferedImage.TYPE_INT_RGB);
Graphics2D imageGraphics = image.createGraphics();
GradientPaint gp = new GradientPaint(
20f,
20f,
Color.red,
380f,
280f,
Color.orange);
imageGraphics.setPaint(gp);
imageGraphics.fillRect(0, 0, 400, 300);
JLabel textLabel = new JLabel(title);
textLabel.setSize(textLabel.getPreferredSize());
Dimension d = textLabel.getPreferredSize();
BufferedImage bi = new BufferedImage(
d.width,
d.height,
BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics();
g.setColor(new Color(255, 255, 255, 128));
g.fillRoundRect(
0,
0,
bi.getWidth(f),
bi.getHeight(f),
15,
10);
g.setColor(Color.black);
textLabel.paint(g);
Graphics g2 = image.getGraphics();
g2.drawImage(bi, 20, 20, f);
ImageIcon ii = new ImageIcon(image);
JLabel imageLabel = new JLabel(ii);
f.getContentPane().add(imageLabel);
f.pack();
f.setLocationByPlatform(true);
f.setVisible(true);
}
});
}
}

Related

Java 2D rotate BufferedImage

This question was answered many time but I still can't apply it to my situation.
I want to rotate image on 90 degrees clockwise.
I'm currently having following code:
private void writeImage(BufferedImage sourceImage, String Path) throws IOException {
BufferedImage result;
Graphics2D g;
AffineTransform at = new AffineTransform();
//Do some magic right here to correctly rotate the image itself
if (sourceImage.getWidth() > sourceImage.getHeight()) {
//Do some stuff that somehow works:
result = new BufferedImage(sourceImage.getHeight(null), sourceImage.getWidth(null), BufferedImage.TYPE_INT_RGB);
g = result.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// Anti-alias!
g.translate((result.getHeight() - result.getWidth()) / 2, (result.getHeight() - result.getWidth()) / 2);
g.rotate(Math.toRadians(90f), sourceImage.getHeight() / 2, sourceImage.getWidth() / 2);//simple try
} else {
result = new BufferedImage(sourceImage.getWidth(null), sourceImage.getHeight(null), BufferedImage.TYPE_INT_RGB);
g = result.createGraphics();
}
//result = new BufferedImage(sourceImage.getWidth(null), sourceImage.getHeight(null), BufferedImage.TYPE_INT_RGB);
//g = result.createGraphics();
/*
if (result.getWidth() > result.getHeight()) {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// Anti-alias!
//g.translate(170, 0);
g.rotate(Math.toRadians(90));
//g.translate((result.getHeight() - result.getWidth()) / 4, (result.getHeight() - result.getWidth()) / 4);
//g.rotate(Math.PI / 2, result.getHeight() / 2, result.getWidth() / 2);
//g.drawImage(sourceImage, 0, 0, result.getHeight(), result.getWidth(), Color.WHITE, null);
//AffineTransformOp op = new AffineTransformOp(rotateClockwise90(result), AffineTransformOp.TYPE_BILINEAR);
//op.filter(sourceImage, result);
int tempHeight = result.getHeight();
int tempWidth = result.getWidth();
BufferedImage rotated = resize(result, tempHeight, tempWidth);
//result = rotated;
result = resize(result, result.getHeight(), result.getWidth());
}*/
g.drawImage(sourceImage, 0, 0, result.getWidth(), result.getHeight(), Color.WHITE, null);
//g.drawImage(sourceImage, at, null);
g.dispose();
//BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
//g = bufferedImage.createGraphics();
//Color.WHITE estes the background to white. You can use any other color
//g.drawImage(image, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), Color.WHITE, null);
File output = new File(Path);
OutputStream out = new FileOutputStream(output);
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
ImageOutputStream ios = ImageIO.createImageOutputStream(out);
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
if (param.canWriteCompressed()) {
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(IMAGE_QUALITY);
}
writer.write(null, new IIOImage(result, null, null), param);
out.close();
ios.close();
writer.dispose();
}
Current Result
The source image and 'BufferedImage sourceImage' looks like this:
Source Image
And what I expect to see is this:
Expected
Thanks!
Here is a more general solution that will allow rotation of any specified degrees:
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.*;
import javax.swing.border.*;
public class Rotation
{
public static BufferedImage rotateImage(BufferedImage original, 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 = original.getWidth();
double height = original.getHeight();
int w = (int)(width * cos + height * sin);
int h = (int)(width * sin + height * cos);
// Create empty image and fill in background
BufferedImage rotated = new BufferedImage(w, h, original.getType());
Graphics2D g2 = rotated.createGraphics();
g2.setPaint(UIManager.getColor("Panel.background"));
g2.fillRect(0, 0, w, h);
// Rotate the image
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(original, at);
g2.dispose();
return rotated;
}
private static void createAndShowGUI()
{
BufferedImage bi;
try
{
String path = "mong.jpg";
ClassLoader cl = Rotation.class.getClassLoader();
bi = ImageIO.read( cl.getResourceAsStream(path) );
}
catch (Exception e) { return; }
JLabel label = new JLabel( new ImageIcon( bi ) );
label.setBorder( new LineBorder(Color.RED) );
label.setHorizontalAlignment(JLabel.CENTER);
JPanel wrapper = new JPanel();
wrapper.add( label );
JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
slider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
int value = slider.getValue();
BufferedImage rotated = Rotation.rotateImage(bi, Math.toRadians(value) );
label.setIcon( new ImageIcon(rotated) );
}
});
JFrame frame = new JFrame("Rotation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(wrapper, BorderLayout.CENTER);
frame.add(slider, BorderLayout.PAGE_END);
frame.setSize(600, 600);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}
Try
g.drawImage(sourceImage, 0, 0, sourceImage.getWidth(), sourceImage.getHeight(), Color.WHITE, null);

JLabel: Squish text if it doesn't fit

I have JLabels in a constrained space (JTable) and when the text inside the label is too long, it's truncated. Is there a way to make the text fit in the allotted space by only horizontal squishing?
See the upper Jlabel in these examples:
The text is HTML formatted so I can't just drawstring on a custom JPanel component myself. There's no icon.
Since I've solved this question while typing it, in accordance with meta I'll share the answer.
I set this as the UI for the JLabel:
It renders the text to an off-screen image, then resizes that image to the JLabel's proportions.
[Edit] This doesn't work correctly with transparent labels or labels with empty HTML text.
// Copied and modified from BasicLabelUI
private static class SquishLabelUI extends BasicLabelUI {
private final Rectangle paintIconR = new Rectangle();
private final Rectangle paintTextR = new Rectangle();
private String layout(JLabel label, FontMetrics fm, int width, int height) {
Insets insets = label.getInsets(null);
String text = label.getText();
Rectangle paintViewR = new Rectangle(insets.left,
insets.top,
width - (insets.left + insets.right),
height - (insets.top + insets.bottom));
paintIconR.setBounds(0, 0, 0, 0);
paintTextR.setBounds(0, 0, 0, 0);
return layoutCL(label, fm, text, null, paintViewR, paintIconR, paintTextR);
}
#Override
public void paint(Graphics g, JComponent c) {
JLabel label = (JLabel)c;
layout(label, SwingUtilities2.getFontMetrics(label, g), c.getWidth(), c.getHeight());
View v = (View)c.getClientProperty(BasicHTML.propertyKey);
Dimension size = getPreferredSize(label);
BufferedImage img = label.getGraphicsConfiguration()
.createCompatibleImage(size.width, size.height, TRANSLUCENT);
Graphics2D g2 = img.createGraphics();
try {
g2.setColor(label.getBackground());
g2.setClip(0, 0, size.width, size.height);
g2.fillRect(0, 0, size.width, size.height);
v.paint(g2, new Rectangle(0, 0, size.width, size.height));
int renderWidth = Math.min(size.width, paintTextR.width);
Image img2 = img.getScaledInstance(renderWidth, paintTextR.height, Image.SCALE_SMOOTH);
g.drawImage(img2, paintTextR.x, paintTextR.y, null);
} finally {
g2.dispose();
}
}
}

Painting JLabel cuts off HTML Text

I'm trying to paint a JLabel to a BufferedImage using html as text but it always prints the text in the middle (vertically), and cuts off the text on the right.
Here is my code:
public static void test() throws IOException
{
int width = 100;
JLabel label = new JLabel();
label.setText("<html><body><p>asdf asdfasdf asdfsdf asdfasdf asdfasdf asdfasdfasdfasdf asdfasdfasdfa sdfasd fasdf asdfasdf asdfasdf asdfasdfasdfa sdfasdf</p></body></html>");
Dimension size = getPreferredSize(label.getText(), true, width);
label.setSize(size);
BufferedImage image =
new BufferedImage(
label.getWidth(),
label.getHeight(),
BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0, 0, 500, 900);
label.paint(g);
ImageIO.write(image, "png", new File("testImage.png"));
}
private static final JLabel resizer = new JLabel();
public static java.awt.Dimension getPreferredSize(
String html,
boolean width,
int prefSize)
{
resizer.setText(html);
View view =
(View) resizer
.getClientProperty(javax.swing.plaf.basic.BasicHTML.propertyKey);
view.setSize(width ? prefSize : 0, width ? 0 : prefSize);
float w = view.getPreferredSpan(View.X_AXIS);
float h = view.getPreferredSpan(View.Y_AXIS);
return new java.awt.Dimension((int) Math.ceil(w), (int) Math.ceil(h));
}
And here is the resulting image:
I think the html word wrapping is handled by something in the swing thread loop, if you are doing this form that loop as a actionlistener then it can't recalculate the html

Bold text on image

I want to append bold text on image, only selected text should be bold.
String word="This is dummy text, this should be BOLD"
final BufferedImage image = ImageIO.read(new File(Background));
Graphics g = image.getGraphics();
g.drawString(word, curX, curY);
g.dispose();
ImageIO.write(image, "bmp", new File("output.bmp"));
You want to use an AttributedString and pass its iterator to drawString
static String Background = "input.png";
static int curX = 10;
static int curY = 50;
public static void main(String[] args) throws Exception {
AttributedString word= new AttributedString("This is text. This should be BOLD");
word.addAttribute(TextAttribute.FONT, new Font("TimesRoman", Font.PLAIN, 18));
word.addAttribute(TextAttribute.FOREGROUND, Color.BLACK);
// Sets the font to bold from index 29 (inclusive)
// to index 33 (exclusive)
word.addAttribute(TextAttribute.FONT, new Font("TimesRoman", Font.BOLD, 18), 29,33);
word.addAttribute(TextAttribute.FOREGROUND, Color.BLUE, 29,33);
final BufferedImage image = ImageIO.read(new File(Background));
Graphics g = image.getGraphics();
g.drawString(word.getIterator(), curX, curY);
g.dispose();
ImageIO.write(image, "png", new File("output.png"));
}
output.png:
You can set a Font on the Graphics object before you draw the String like this:
Font test = new Font("Arial",Font.BOLD,20);
g.setFont(test);
If you only want one word bold you'll have to call drawString twice, and set the font to bold only the second time.
Maybe this one will help - curX,curY should be updated after the first drawString probably, otherwise it will look quite nasty. :)
String word="This is text, this should be ";
final BufferedImage image = ImageIO.read(new File(Background));
Graphics g = image.getGraphics();
g.drawString(word, curX, curY);
Font f = new Font("TimesRoman", Font.Bold, 72);
g.setFont(f);
String word="BOLD";
g.drawString(word, curX, curY);
g.dispose();
ImageIO.write(image, "bmp", new File("output.bmp"));

Customize icon in Drag Drop Event?

I am dragging and dropping the jTable cell from one jTable to another jTable.For Now it is showing me default drag drop icon.
I am using TransferHandler class to implement this.
I Override getDragImage(image) to put my customize image But it is not working.
This way i implemented my code Implementation
I tried this code into this method.
File newFile = new File("./dragImage.jpeg");
Font font = new Font("Tahoma", Font.PLAIN, 11);
FontRenderContext frc = new FontRenderContext(null, true, true);
Rectangle2D bounds = font.getStringBounds(l_value, frc);
int w = (int) bounds.getWidth();
int h = (int) bounds.getHeight();
BufferedImage image = new BufferedImage(10,10, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, 10, 10);
g.setColor(Color.BLACK);
g.setFont(font);
g.drawString(l_value, (float) bounds.getX(), (float) -bounds.getY());
g.dispose();
return image;
This code is working in my main method but here in this function it is not working.

Categories

Resources