Java rotated image turns all black? - java

I am making a basic java application and trying to rotate an image. I wrote the following quick method
private Image rotate(double degs){
ImageIcon img = new ImageIcon("src/inc/img/char_male.png");
Image temp = new BufferedImage(img.getIconWidth(), img.getIconHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = (Graphics2D) temp.getGraphics();
g2.rotate(Math.toRadians(degs));
g2.drawImage(img.getImage(), 0, 0, Color.WHITE, null);
System.out.println("Rotating "+degs);
g2.dispose();
return temp;
}
The problem is when I run this and repaint the GUI, the image turns pure black. Am I doing something wrong with the BufferedImage creation? I am changing the GUI in the repaint using a JLabel,
label.setIcon(new ImageIcon(rotate(90)));

You need to rotate and translate at the same time so that the center of rotation is the center of the image. The AffineTransform rotate method has an overload for this as does the Graphics2D rotate method. For e.g., what if you try,...
private Image rotate(double degs){
ImageIcon img = new ImageIcon("src/inc/img/char_male.png"); // why an ImageIcon???
Image temp = new BufferedImage(img.getIconWidth(), img.getIconHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = (Graphics2D) temp.getGraphics();
g2.rotate(Math.toRadians(degs), img.getIconWidth()/2, img.getIconHeight()/2); // changed
g2.drawImage(img.getImage(), 0, 0, Color.WHITE, null);
System.out.println("Rotating "+degs);
g2.dispose();
return temp;
}
Sorry, here's the corrected code:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
public class ImageRotate {
private static final String IMAGE_PATH = "src/yr2011/images/guitar_3406632_n.jpg";
public static void main(String[] args) {
try {
BufferedImage image = ImageIO.read(new File(IMAGE_PATH));
ImageIcon icon = new ImageIcon(image);
JOptionPane.showMessageDialog(null, new JLabel(icon));
icon = new ImageIcon(rotate(image, 90));
JOptionPane.showMessageDialog(null, new JLabel(icon));
} catch (IOException e) {
e.printStackTrace();
}
}
private static Image rotate(Image image, double degs) {
int width = image.getWidth(null);
int height = image.getHeight(null);
BufferedImage temp = new BufferedImage(height, width, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = temp.createGraphics();
g2.rotate(Math.toRadians(degs), height / 2, height / 2);
g2.drawImage(image, 0, 0, Color.WHITE, null);
g2.dispose();
return temp;
}
}

I don't use Java, so that I can't tell if there's something wrong with your code, but a common error when doing image rotation is rotating out of the viewport. When you imagine the original image sitting at the coordinate origin, rotating it by 90 degrees moves the image below the x-axis (or left of the y-axis, depending on the direction). In both cases the rotated image leaves the viewport and you get an empty image. The solution is to shift the rotated image back to place.

I had the same probleme and I solved it in an other way:
My picture had a transparent background but I didn't know it because I look it always on white background. Anyway, I solved my problem when I use
BufferedImage temp = new BufferedImage(height, width, BufferedImage.TYPE_INT_ARGB);
instead of
BufferedImage temp = new BufferedImage(height, width, BufferedImage.TYPE_INT_RGB);
I think that graphics2d work with a black background if you don't precise transparent type.

Related

How do I create a kaleidoscopic photo with this?

For my assignment I need to turn this singular picture.
Into this:
I've tried using negatives and reversing it manually but that didn't work out.
DrawingImages.java
```java
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
public class DrawingImages
{
private Picture newCanvas = null;
private Graphics g = null;
private Graphics2D g2 = null;
private Picture pic1 = null;
private Color color = null;
int height= 250;
int width = 250;
DrawingImages(Picture canv, Picture p1)
{
newCanvas = canv;
newCanvas.setAllPixelsToAColor(Color.BLACK);
g = newCanvas.getGraphics();
g2 = (Graphics2D)g;
pic1 = p1;
}
public Picture drawPicture()
{
//Flip the image both horizontally and vertically
g2.drawImage(image, x+(width/2), y+(height/2), -width, -height, null);
//Flip the image horizontally
g2.drawImage(image, x+(width/2), y-(height/2), -width, height, null);
//Flip the image vertically
g2.drawImage(image, x-(width/2), y+(height/2), width, -height, null);
return newCanvas;
}
}
```
DrawingImagesTester.java
```java
import java.awt.Color;
public class DrawImagesTester
{
public static void main(String[] args)
{
Picture canvas = new Picture(500, 500);
Picture picture1 = new Picture("flower1.jpg");
DrawingImages draw = new DrawingImages(canvas, picture1, Color.YELLOW);
canvas = draw.drawPicture();
canvas.show();
}
}
You need to mirror the image. The process is actually really simple and is a commonly used trick. You simply need to scale the image in a negative direction, along the axis you want mirrored (and then translate the image so it will re-appear within the user space)
For example...
BufferedImage img = ImageIO.read(new File("/Users/shanew/Downloads/kAJZbDc.jpg"));
BufferedImage mirrored = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
Graphics2D g2d = mirrored.createGraphics();
g2d.scale(-1, 1);
g2d.translate(-mirrored.getWidth(), 0);
g2d.drawImage(img, 0, 0, null);
g2d.dispose();
BufferedImage combined = new BufferedImage(img.getWidth() * 2, img.getHeight(), img.getType());
g2d = combined.createGraphics();
g2d.drawImage(img, 0, 0, null);
g2d.drawImage(mirrored, img.getWidth(), 0, null);
g2d.dispose();
JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(combined)));

Java double buffering with buffered image

After a day of searching, I have given up and decided to ask this question: I can't seem to stop the constant flickering of this program:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Paint {
BufferedImage image0, image1, image2;
double rotation0 = 0.0001;
double rotation1 = 0.0501;
double rotation2 = 3.0001;
double add0 = 0.0001;
double add1 = 0.0016;
double add2 = 0.000001;
private int x() {
return Main.getX() / 2;
}
private int y() {
return Main.getY() / 2;
}
public Paint() {
try {
image0 = ImageIO.read(new File("circle1.jpg"));
image1 = ImageIO.read(new File("circle2.jpg"));
image2 = ImageIO.read(new File("circle3.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
public void paint(Graphics g) {
// create the transform, note that the transformations happen
// in reversed order (so check them backwards)
AffineTransform at0 = new AffineTransform();
AffineTransform at1 = new AffineTransform();
AffineTransform at2 = new AffineTransform();
// 4. translate it to the center of the component
at0.translate(x(), y() + 10);
at1.translate(x(), y() + 10);
at2.translate(x(), y() + 10);
// 3. do the actual rotation
rotation0 += add0;
rotation1 += add1;
rotation2 += add2;
at0.rotate(rotation0);
at1.rotate(rotation1);
at2.rotate(rotation2);
// 2. just a scale because this image is big
at0.scale(1, 1);
at1.scale(1, 1);
at2.scale(1, 1);
// 1. translate the object so that you rotate it around the
// center (easier :))
at0.translate(-image0.getWidth()/2, -image0.getHeight()/2);
at1.translate(-image1.getWidth()/2, -image1.getHeight()/2);
at2.translate(-image2.getWidth()/2, -image2.getHeight()/2);
// draw the image
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(image0, at0, null);
g2d.drawImage(image1, at1, null);
g2d.drawImage(image2, at2, null);
}
}
IMPORTANT: Everything works but the double buffering, which causes the image to flicker. If you don't mind, please provide code along with the answer.
Double buffering consists into drawing your content to an internal image and then draw that image on screen. By doing that, the image is never partially printed.
So, instead of drawing your 3 images directly in your Graphics object, try drawing them into a new BufferedImage and draw that image in the Graphics object (screen).
See this official page for more info: https://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html
I assume the usage is in a JPanel child. By default a JPanel is double-buffered.
JPanel panel new JPanel() {
Paint paint = new Paint();
#Override
public void paintComponent(Graphics g) {
paint.paint(g);
}
};
.. add the panel to the JFrame.
This should work in java swing. Java awt components is another obsolete matter.

Java - Method that resizes, rotates and draws a image after arguments

im trying to make a method in java that will resize rotate and draw a image after given arguments.
It does not work tho. Idk how? Btw is it posible to do this with the normal Graphic class and not Graphic2D ? Thanks!
public void drawResizedAndRotatedImage(Image image, Graphics g, int x, int y, int sizeX, int sizeY, double degrees){
//Resize
BufferedImage im = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_4BYTE_ABGR);
#SuppressWarnings("unused")
Graphics g2 = (Graphics)im.getGraphics();
//Rotate
ImageIcon imageIcon = new ImageIcon(image);
BufferedImage bufferedImage = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2d = (Graphics2D)bufferedImage.getGraphics();
g2d.rotate(Math.toRadians(degrees), imageIcon.getIconWidth() / 2, imageIcon.getIconHeight() / 2);
//Draw
g.drawImage(image, x, y, sizeX, sizeY, null);
}
Okay, so you create a BufferedImage and grab it's Graphics context...
BufferedImage im = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_4BYTE_ABGR);
Graphics g2 = (Graphics)im.getGraphics();
And do nothing with it...
You then create a second BufferedImage, grab it's Graphics context, set it's rotational context and paint nothing to it...
BufferedImage bufferedImage = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2d = (Graphics2D)bufferedImage.getGraphics();
g2d.rotate(Math.toRadians(degrees), imageIcon.getIconWidth() / 2, imageIcon.getIconHeight() / 2);
You then paint the original image to the supplied Graphics context...
g.drawImage(image, x, y, sizeX, sizeY, null);
Having achieved nothing at all...
I think you need to start by taking a read through Transforming Shapes, Text, and Images to get some grounding on the basics...
Transformations are compounding, they also only effect whatever is painted to the Graphics context AFTER they have been applied.
The simplest approach would actually be to use a AffineTransform
double scaleWidth = (double)sizeX / (double)image.getWidth(this);
double scaleHeight = (double)sizeY / (double)image.getHeight(this);
BufferedImage img = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
AffineTransform at = new AffineTransform();
at.scale(scaleWidth, scaleHeight);
at.rotate(Math.toRadians(degrees), image.getWidth(this) / 2d, image.getHeight(this) / 2d);
g2d.setTransform(at);
g2d.drawImage(image, sizeX / 2, sizeY / 2, null);
g2d.dispose();
// And finally, the result...
g.drawImage(img, x, y, null);
For example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestImage {
public static void main(String[] args) {
new TestImage();
}
public TestImage() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
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 original;
public TestPane() {
try {
original = ImageIO.read(new File("Your image here"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public Image scaleAndRotate(Image image, int sizeX, int sizeY, double degrees) {
double scaleWidth = (double)sizeX / (double)image.getWidth(this);
double scaleHeight = (double)sizeY / (double)image.getHeight(this);
BufferedImage img = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
AffineTransform at = new AffineTransform();
at.scale(scaleWidth, scaleHeight);
at.rotate(Math.toRadians(degrees), image.getWidth(this) / 2d, image.getHeight(this) / 2d);
g2d.setTransform(at);
g2d.drawImage(image, sizeX / 2, sizeY / 2, null);
g2d.dispose();
return img;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int scaleWidth = getWidth() / 2;
int scaleHeight = getHeight() / 2;
Image img = scaleAndRotate(original, scaleWidth, scaleHeight, 45.0);
int x = (getWidth() - img.getWidth(this)) / 2;
int y = (getHeight()- img.getHeight(this)) / 2;
g2d.drawImage(img, x, y, this);
g2d.dispose();
}
}
}
You may also like to take a read through...
Java: maintaining aspect ratio of JPanel background image
Quality of Image after resize very low -- Java
For discussions about scaling algorithms and techniques
You should also know that the size of an image when it rotates also changes, have a look at (one of my favourite answers to refer to) Rotate an image in java for more details about how to calculate the resulting image size of a rotated image...

Convert text content to Image

Is there out any Java library that allows converting text content to image files? I only know of ImageMagick (JMagick in this case) but I wouldn't like to install any external binaries (my app will be deployed as a .war file in a Tomcat server so I don't want any other dependencies more than Java).
For example, from the string "Hello", I would like to generate this simple image:
The Graphics 2D API should be capable of achieving what you need. It has some complex text handling capabilities as well.
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class TextToGraphics {
public static void main(String[] args) {
String text = "Hello";
/*
Because font metrics is based on a graphics context, we need to create
a small, temporary image so we can ascertain the width and height
of the final image
*/
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
Font font = new Font("Arial", Font.PLAIN, 48);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
int width = fm.stringWidth(text);
int height = fm.getHeight();
g2d.dispose();
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.setFont(font);
fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
try {
ImageIO.write(img, "png", new File("Text.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Also check out Writing/Saving and Image
WARNING I used this to generate 90k PNG images only to find that they can be viewed in IE but not in Chrome Version 70.0.3538.77
The above code works just fine for me (I changed the text color to WHITE so I could see it in chrome)
I was using Chrome 70.0.3538.77 on Mac OS Mojave 10.14 using Java 10.0.2. The resulting image was 4778x2411 pixels ...
Updated...
On IE that is black on white but on Chrome that is black on black. Yet I set background to white.
So what you're telling me is, a transparent PNG is been displayed differently on different browsers, because the browsers use different default backgrounds ... why are you surprised by this?
The original solution, deliberately, used a transparent based image. This is evident by the use of BufferedImage.TYPE_INT_ARGB when creating the image, which is applying a Alpha (A) based RGB color model.
This is unexpected as there is g2d.setBackground(Color.white).
No, actually, it is entirely expected, if only you understood what setBackground actually does and how it should be used
From the JavaDocs
Sets the background color for the Graphics2D context. The background
color is used for clearing a region. When a Graphics2D is constructed
for a Component, the background color is inherited from the Component.
Setting the background color in the Graphics2D context only affects
the subsequent clearRect calls and not the background color of the
Component. To change the background of the Component, use appropriate
methods of the Component.
From the "sounds" of things, you want a non-transparent image, with a filled background color. So, once again, it's off to the JavaDocs and a little bit of reading would have lead you to BufferedImage.TYPE_INT_RGB, which removes the Alpha channel, but you'd still have to fill the background of the image.
For this, I'd use Graphics2D#setColor and Graphics2D#fillRect, only because it works.
So, you'd end up with a modified version of the above which might look something like...
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
g2d = img.createGraphics();
//...
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
g2d.setColor(Color.BLACK);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
try {
ImageIO.write(img, "png", new File("Text.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
If I change to "jpg" then I get orange/pink text on black background on both IE and Chrome
Well, this is related to a well known, and sadly, common issue/bug in ImageIO, which attempts to apply the alpha channel of transparent color models to the JPG, which doesn't support alpha channels.
See Issue using ImageIO.write jpg file: pink background for more details.
But the basic solution is to either use PNG, which supports alpha channels, or to use a non-transparent image.
So, the long and short of all this is. The problem is NOT with the original answer, nor is it with ImageIO, BufferedImage, Graphics, the AWT library, Chrome or IE, but with your lack of understanding of how these APIs (and the example) works.
Without any external libraries, do the following:
Measure the text size in pixels (see Measuring Text)
Create a java.awt.image.BufferedImage in the right size for the text
Acquire the graphics object for the BufferedImage using the createGraphics() method
Draw the text
Save the image using the javax ImageIO class
Edit - fixed the link
Consider the following snippet:
public static final HashMap<RenderingHints.Key, Object> RenderingProperties = new HashMap<>();
static{
RenderingProperties.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
RenderingProperties.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
RenderingProperties.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
}
public static BufferedImage textToImage(String Text, Font f, float Size){
//Derives font to new specified size, can be removed if not necessary.
f = f.deriveFont(Size);
FontRenderContext frc = new FontRenderContext(null, true, true);
//Calculate size of buffered image.
LineMetrics lm = f.getLineMetrics(Text, frc);
Rectangle2D r2d = f.getStringBounds(Text, frc);
BufferedImage img = new BufferedImage((int)Math.ceil(r2d.getWidth()), (int)Math.ceil(r2d.getHeight()), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setRenderingHints(RenderingProperties);
g2d.setBackground(Color.WHITE);
g2d.setColor(Color.BLACK);
g2d.clearRect(0, 0, img.getWidth(), img.getHeight());
g2d.setFont(f);
g2d.drawString(Text, 0, lm.getAscent());
g2d.dispose();
return img;
}
Uses only the java Graphics API to create a image based on a font rendered onto a bufferedimage.
demo# For multi line texts #
Pass the file as argument to the program
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
public class TextToGraphics {
public static void main(String[] args){
System.out.println(args[0]);
File file = new File(args[0]);
try{
BufferedReader br = new BufferedReader(new FileReader(file));
StringBuilder sb = new StringBuilder();
String line;
while((line = br.readLine())!=null){
sb.append(line).append("\n");
}
convert(sb.toString(),args[0]+"_img");
System.out.println("Done.");
}
catch(FileNotFoundException e){
e.printStackTrace();
}
}
public static void convert(String text, String img_name) {
String[] text_array = text.split("[\n]");
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
Font font = new Font("Consolas", Font.BOLD, 12);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
int width = fm.stringWidth(getLongestLine(text_array));
int lines = getLineCount(text);
int height = fm.getHeight() * (lines + 4);
g2d.dispose();
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.setFont(font);
fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
for (int i = 1; i <= lines; ++i) {
g2d.drawString(text_array[i - 1], 0, fm.getAscent() * i);
}
g2d.dispose();
try {
String img_path = System.getProperty("user.dir") + "/" + img_name + ".png";
ImageIO.write(img, "png", new File(img_path));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static int getLineCount(String text) {
return text.split("[\n]").length;
}
private static String getLongestLine(String[] arr) {
String max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (max.length() < arr[i].length()) {
max = arr[i];
}
}
return max;
}
}
Here is a simple Program to write Graphics contents to png format.
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.io.File;
import javax.imageio.ImageIO;
class ImageWriteEx extends JPanel{
public void paint(Graphics g){
Image img = createImageWithText();
g.drawImage(img, 20, 20, this);
}
private static BufferedImage createImageWithText(){
BufferedImage bufferedImage = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB);
Graphics g = bufferedImage.getGraphics();
g.drawString("www.stackoverflow.com", 20, 20);
g.drawString("www.google.com", 20, 40);
g.drawString("www.facebook.com", 20, 60);
g.drawString("www.youtube.com", 20, 80);
g.drawString("www.oracle.com", 20, 1000);
return bufferedImage;
}
public static void main(String[] args){
try{
BufferedImage bi = createImageWithText();
File outputfile = new File("save.png");
ImageIO.write(bi, "png", outputfile);
} catch(Exception e){
e.printStackTrace();
}
JFrame frame = new JFrame();
frame.getContentPane().add(new ImageWriteEx());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300,300);
frame.setVisible(true);
}
}
In case someone wants TextImages with several lines. I made some and displayed them with
new ImageIcon(*here the image*)
in JOptionPane (without adding text). That fills the whole JOptionPane nicely. Here the code:
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
public class TextImage
{
public static BufferedImage make(String...textrows)
{
BufferedImage helperImg = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = helperImg.createGraphics();
Font font = *here some font*;
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
String longestText = "";
for(String row: textrows)
{
if(row.length()>longestText.length())
{
longestText = row;
}
}
int width = fm.stringWidth(longestText);
int height = fm.getHeight()*textrows.length;
g2d.dispose();
BufferedImage finalImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
g2d = finalImg.createGraphics();
g2d.setColor(*here some Color*);
g2d.fillRect(0, 0, width, height);
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.setFont(font);
fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
int y = fm.getAscent();
for(String row: textrows)
{
g2d.drawString(row, 0, y);
y += fm.getHeight();
}
g2d.dispose();
return finalImg;
}
}

java.lang.IllegalArgumentException: Number of scaling constants does not equal the number of of color or color/alpha components

I am writing aplha composite test app based on this example
/* Create an ARGB BufferedImage */
BufferedImage img = (BufferedImage)image;//ImageIO.read(imageSrc);
int w = img.getWidth(null);
int h = img.getHeight(null);
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR_PRE);
Graphics g = bi.getGraphics();
g.drawImage(img, 0, 0, null);
/* Create a rescale filter op that makes the image 50% opaque */
float[] scales = { 1f, 1f, 1f, 1f };
float[] offsets = new float[4];
RescaleOp rop = new RescaleOp(scales, offsets, null);
/* Draw the image, applying the filter */
g2d.drawImage(bi, rop, 0, 0);
source link: http://download.oracle.com/javase/tutorial/2d/images/drawimage.html
It works fine with simple images but with photos (jpg etc) I get this exception like:
java.lang.IllegalArgumentException:
Number of scaling constants does not
equal the number of of color or
color/alpha components
To be more clear... Here is my adapted test code class. This code style throws the exception...
public class ImageTest extends JLabel {
public Image image;
private BufferedImage bImage;
ImageObserver imageObserver;
float[] scales = {1f, 1f, 1f, 1f};
float[] offsets = new float[4];
RescaleOp rop;
int width;
int height;
public ImageTest(ImageIcon icon) {
width = icon.getIconWidth();
height = icon.getIconHeight();
this.image = icon.getImage();
this.imageObserver = icon.getImageObserver();
//this.bImage=(BufferedImage)image; //previous version (makes exception?)...
this.bImage = new BufferedImage(
width, height, BufferedImage.TYPE_INT_ARGB);
this.bImage.createGraphics().drawImage(
this.image, 0, 0, width, height, imageObserver);
rop = new RescaleOp(scales, offsets, null);
this.repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(this.bImage, rop, 0, 0);
}
public void setRescaleOp(RescaleOp rop) {
this.rop = rop;
}
}//class end
I am not pretty sure where the exception comes from so I need your advice where to look at?
P.S. I suppose it is the IndexColorModel problem but if so I am not sure how to fix it...
Any useful comment is appreciated :)
Andrew
Using the example below and the image you provided, I am unable to reproduce the effect you describe.
I was puzzled that a BufferedImage of TYPE_4BYTE_ABGR_PRE has a ComponentColorModel, in contrast to the more familiar DirectColorModel, but it's an IndexColorModel that cannot be rescaled.
Addendum: Updated code to use filter(), as the previous version was incorrectly reusing the BufferedImage.
Addendum: In another answer, you said,
I don't want to create a new BufferedImage each time. I want to filter the image on the fly using a JSlider.
The example you cited does this by creating the BufferedImage once in the SeeThroughComponent constructor and then adjusting just the RescaleOp in the slider's change handler. It seems quite responsive.
Addendum: In an edit to your question, you mention that the IllegalArgumentException may arise when encountering an image having an IndexColorModel. I am able to reproduce this using, e.g. TYPE_BYTE_INDEXED. You may be able to work around such images by trapping the exception and rendering them separately as shown here.
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/** #see https://stackoverflow.com/questions/5838842 */
public class RescaleOpTest extends JPanel {
public static final String LINK =
"http://www.freeimagehosting.net/uploads/576c64ef7b.png";
public RescaleOpTest() {
this.setLayout(new GridLayout(1, 0));
Image img = null;
try {
img = ImageIO.read(new URL(LINK));
// img = ImageIO.read(new File("image.jpg"));
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
int w = img.getWidth(null);
int h = img.getHeight(null);
BufferedImage bi = new BufferedImage(
w, h, BufferedImage.TYPE_4BYTE_ABGR_PRE);
Graphics2D g = bi.createGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
/* Create a rescale filter op that makes the image 75% opaque */
float[] scales = {1f, 1f, 1f, 0.75f};
float[] offsets = new float[4];
RescaleOp rop = new RescaleOp(scales, offsets, null);
bi = rop.filter(bi, null);
this.add(new JLabel(new ImageIcon(img)));
this.add(new JLabel(new ImageIcon(bi)));
}
private void display() {
JFrame f = new JFrame("RescaleOpTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new RescaleOpTest().display();
}
});
}
}

Categories