.setIcon() image does not display when KeyListener fired - image

So I'm making like a digital brochure thing for Switzerland. I wanted to make it so that different images appear when pressing certain keys. Here's my code so far. When I press 1, 'mainpage' is displayed. However, when I press 4, 'government' isn't displayed.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class Main extends JFrame {
JFrame frame;
JLabel label;
JLabel image2;
JLabel title;
JLabel image;
JLabel footnote;
JPanel panel;
JScrollPane scrollPane;
ImageIcon mainpage;
ImageIcon government;
ImageIcon icon3;
int page = 1;
public Main() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel(new BorderLayout());
panel.setPreferredSize(new Dimension(800, 800));
label = new JLabel();
image2 = new JLabel();
title = new JLabel();
image = new JLabel();
footnote = new JLabel();
panel.add(image, BorderLayout.LINE_START);
panel.add(label, BorderLayout.LINE_END);
panel.add(image2, BorderLayout.CENTER);
panel.add(title, BorderLayout.PAGE_START);
panel.add(footnote, BorderLayout.PAGE_END);
title.setFont(new Font("Serif", Font.PLAIN, 20));
scrollPane = new JScrollPane(panel);
frame.add(scrollPane, BorderLayout.CENTER);
mainpage = new ImageIcon("mainpage.png");
government = new ImageIcon("Parliament-Building-Bern-Switzerland.png");
icon3 = new ImageIcon("6kcsr1gjpeia1.png");
frame.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
char key = e.getKeyChar();
if (key == '1') {
image.setIcon(mainpage);
title.setText("La Communauté de Suisse");
}
if (key == '2') {
title.setText("<html><body style='width: 400px; text-align:justify'>La Cuisine de la Suisse</body></html>");
label.setText("<html><body style='width: 400px; text-align:justify'>Let us start by discussing Swiss cuisine. The foods of Switzerland is diverse and tasty. It ranges from the world-famous Swiss cheese to the delicious Swiss chocolate. Here are some Swiss delicacies that we curated and have decided to showcase.<br><br> Firstly, we have the cheese fondue - a type of melted cheese with bread cubes.</body></html>");
footnote.setText("Left - Cheese fondue. Right - Swiss cheese.");
}
if (key == '3') {
title.setText("<html><body style='width: 400px; text-align:justify'>L'écosystème de la Suisse</body></html>");
label.setText("<html><body style='width: 400px; text-align:justify'>Switzerland has over 230 natural environments, including meadows, moors, and forests. Forests. Altogether, they are home to around 64,000 species of plants and animals. Of these, only 45,890 are recorded, leaving much to be explored. It has been determined that such levels of biodiversity are due to Switzerland's inherently varied climate and landscape. </body></html>");
}
if (key == '4') {
title.setText("<html><body style='width: 400px; text-align:justify'>Le Gouvernement de la Suisse</body></html>");
image.setIcon(government);
label.setText("<html><body style='width: 400px; text-align:justify'> The government of Switzerland, like most states, is built from its constitutional framework. The Constitution of Switzerland was first drafted in 1848, where it heavily imitated the constitution of the USA. It was heavily revised in 1874, then again in 2000. It includes more than 200 articles, establishing the rights, powers, and privileges of the nation’s citizens and governors.<br><br>The government itself operates similarly to other democracies. The Federal government controls national and international affairs. It handles subjects like internal and external security, the military, and transportation. Legislative power is spread through the two halves of the National Assembly – the National Council, the lower house, which operates relatively similarly to the Canadian House of Commons, and the Council of Nations, the upper house and comparable to the Canadian senate.<br><br>Now, let us discuss the judicial system. It is based on the Napoleonic Code and follows a three-level court structure. Cantonal courts, situated at the first level, deal with most cases. The second level comprises higher courts that review the decisions of lower courts. The final stage is the Federal Supreme Court, which serves as the highest authority and hears appeals of lower courts' judgments. <br><br>Finally, on the executive side is the collegial (i.e., power is shared equally) Federal Council. It consists of seven members, and each presides over a certain department in the Federal government. </body></html>");
}
}
#Override
public void keyPressed(KeyEvent e) { }
#Override
public void keyReleased(KeyEvent e) { }
});
frame.setSize(500, 500);
frame.setVisible(true);
}
public static void main(String[] args) {
new Main();
}
}
I double-checked the image paths. Nope, nothing. Hell, I even asked ChatGPT, it offered no solution.

Related

why does object.variable work in the main class and in other classes?

I am currently building Space Invaders in Processing and I do not absolutely understand why this happens, it is hard to explain, so here is all the code that goes with the game:
SpaceInvaders.pde:
/* Jordan Green
April 11th, 2018
This is the main class for the game
Space Invaders.
This is what sets up the game.
*/
//My objects declared.
Alien aliens;
Player player;
Score score;
PImage img;
//sets up the variables and gives them values.
void setup() {
aliens = new Alien();
player = new Player();
score = new Score();
size (600, 600);
img = loadImage("Space Background.jpg");
}
//draws out the program.
void draw() {
background(0);
image(img, 0, 0, height, width);
player.show();
player.move();
player.playerLives();
player.alienDie();
aliens.show();
aliens.move();
score.show();
if (player.playerLife == 0) {
}
}
void keyPressed() {
if (key == ' ') {
player.shoot();
}
}
My question is why does an object.variable work on Processing? It's something I do not understand.
Jordan
Why wouldn't it work?
This is a fundamental feature of objects in Java, which Processing is built on top of. If you have a class that contains variables or functions, you can reference those variables or functions using the . dot operator.
Here's an example:
class MyClass{
int x = 42;
void sayHello(){
println("hello");
}
}
MyClass myInstanceOfMyClass = new MyClass();
println(myInstanceOfMyClass.x);
myInstanceOfMyClass.sayHello();
In Java you can mark variables and functions as private to restrict access, but this is less common in Processing.
You can read more about classes in the reference or in this tutorial.

How to populate a tableview cell with an image from Sqlite database in JavaFX?

I am trying to populate a tableView cell with an image stored on a Sqlite database using JavaFX. I have found some really good information on here and feel like I am getting pretty close. If there is no image I would like it to keep the constraints to make the cells the same size always. The images stored on the database are 300x300, but the rows will be much smaller. So far the code I have is :
public void buildDataAseptic(){
listNum = 1;
data = FXCollections.observableArrayList();
try{
String SQL = "Select * from aseptic_parts_list"; //Order By id
ResultSet rs = con.createStatement().executeQuery(SQL);
while(rs.next()){
Part cm = new Part();
cm.id.set(listNum++);
if (rs.getBlob("image") != null ) {
Blob blob = rs.getBlob("image");
byte[] ndata = blob.getBytes(1, (int) blob.length());
image = new Image(new ByteArrayInputStream(ndata));
ImageView imageView = new ImageView();
imageView.setImage(image);
imageView.setFitWidth(70);
imageView.setFitHeight(80);
cm.image.set(image);
}
cm.vendor_part_number.set(rs.getString("vendor_part_number"));
cm.description.set(rs.getString("description"));
cm.quantity.set(rs.getInt("quantity"));
cm.vendor_name.set(rs.getString("vendor_name"));
cm.model_number.set(rs.getString("model_number"));
cm.equipment_id.set(rs.getString("equipment_id"));
data.add(cm);
}
tableView.setItems(data);
}
catch(Exception e){
e.printStackTrace();
System.out.println("Error on Building Data" + e.getMessage());
}
filterData();
//filterEquipIDData();
}
this is just one particular method that is called from a comboBox. All of the other data is populating fine in the table except the image. In the initialize() method I have the columns set up as:
assert tableView != null;
idCol.setCellValueFactory(
new PropertyValueFactory<Part, Integer>("id"));
imgCol.setCellValueFactory(
new PropertyValueFactory<Object,ImageView>("image"));
pnCol.setCellValueFactory(
new PropertyValueFactory<Part,String>("vendor_part_number"));
descCol.setCellValueFactory(
new PropertyValueFactory<Part,String>("description"));
quantityCol.setCellValueFactory(
new PropertyValueFactory<Part,Integer>("quantity"));
venCol.setCellValueFactory(
new PropertyValueFactory<Part,String>("vendor_name"));
mnCol.setCellValueFactory(
new PropertyValueFactory<Part,String>("model_number"));
equipmentIDCol.setCellValueFactory(
new PropertyValueFactory<Part,String>("equipment_id"));
The Part class where the image object is stored is:
public SimpleObjectProperty<Image> image = new SimpleObjectProperty<>();
public Object getImage() {
return image.get();
}
I have been fiddling with this for a few days now and feel pretty close, just no cigar, please help and thanks!
Here is an example for populating TableView cells with images.
The key to the solution is to set the cell value factory and the cell factory appropriately:
TableColumn<Fish, Image> imageColumn = new TableColumn<>("Picture");
imageColumn.setCellValueFactory(new PropertyValueFactory<>("image"));
imageColumn.setCellFactory(param -> new ImageTableCell<>());
Where the ImageTableCell class contains an ImageView as the graphic for the cell and updates the ImageView as the underlying image data changes:
private class ImageTableCell<S> extends TableCell<S, Image> {
final ImageView imageView = new ImageView();
ImageTableCell() {
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
#Override
protected void updateItem(Image item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
imageView.setImage(null);
setText(null);
setGraphic(null);
}
imageView.setImage(item);
setGraphic(imageView);
}
}
One thing to note about this implementation is that it assumes that all images are loaded up into the underlying data structure for the table. This means that if you had a lot of rows in the table, you would be consuming massive amounts of data as all images would be loaded into memory. An alternate solution would be for the underlying data structure just to store the address (url) of the image rather than the image data itself, then load up the image in the cell factory (possibly via an LRU cache mechanism). The trade-off between the different approaches, is speed of operation of the GUI and resources consumed as the user interacts (which is what the all in-memory approach here optimizes for), versus a slower GUI but reduced memory footprint (which is what dymanically loading images in the updateItem call would optimize for). In general, I feel it is best to try to keep the speed of the updateItem call very quick, which is why the solution is presented as is.
I won't supply a sample which also integrates SQLLite as I have no knowledge of that technology, so further integration of the solution with a database system is left up to the reader.
Complete Code
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.*;
import javafx.stage.Stage;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class ImageTable extends Application {
#Override
public void start(Stage stage) {
List<Fish> fish = Arrays.stream(fishData)
.map(data -> new Fish(data[0], new Image(data[1])))
.collect(Collectors.toList());
TableView<Fish> tableView = new TableView<>(FXCollections.observableList(fish));
TableColumn<Fish, String> nameColumn = new TableColumn<>("Name");
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
tableView.getColumns().add(nameColumn);
TableColumn<Fish, Image> imageColumn = new TableColumn<>("Picture");
imageColumn.setCellValueFactory(new PropertyValueFactory<>("image"));
imageColumn.setCellFactory(param -> new ImageTableCell<>());
tableView.getColumns().add(imageColumn);
stage.setScene(new Scene(tableView));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
// image license: linkware - backlink to http://www.fasticon.com
private static final String[][] fishData = {
{ "Blue Fish", "http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Blue-Fish-icon.png" },
{ "Red Fish", "http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Red-Fish-icon.png" },
{ "Yellow Fish", "http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Yellow-Fish-icon.png" },
{ "Green FIsh", "http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Green-Fish-icon.png" }
};
private class ImageTableCell<S> extends TableCell<S, Image> {
final ImageView imageView = new ImageView();
ImageTableCell() {
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
#Override
protected void updateItem(Image item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
imageView.setImage(null);
setText(null);
setGraphic(null);
}
imageView.setImage(item);
setGraphic(imageView);
}
}
public static final class Fish {
private ReadOnlyStringWrapper name;
private ReadOnlyObjectWrapper<Image> image;
public Fish(String name, Image image) {
this.name = new ReadOnlyStringWrapper(name);
this.image = new ReadOnlyObjectWrapper<>(image);
}
public String getName() {
return name.get();
}
public ReadOnlyStringProperty nameProperty() {
return name.getReadOnlyProperty();
}
public Image getImage() {
return image.get();
}
public ReadOnlyObjectProperty<Image> imageProperty() {
return image.getReadOnlyProperty();
}
}
}
Thank you very much jewelsea! I ended up doing what you said, creating another folder to hold the images and using a url to reference the pictures in the folder. The code I used is:
if(rs.getString("image") != null) {
Image img = new Image(rs.getString("image"));
ImageView imageView = new ImageView();
imageView.setImage(img);
cm.image.set(imageView);
imageView.setFitWidth(130);
imageView.setFitHeight(100);
} else {
Image img = new Image("/img/NoImageFound.png");
ImageView imageView = new ImageView();
imageView.setImage(img);
cm.image.set(imageView);
imageView.setFitWidth(130);
imageView.setFitHeight(100);
}
This code queries the database for the image and if there is none there it uses an image i created for image not found. I did this because it was shortening my database results to only queries that had an image, the else shows all results from the database now. It is good to know that this will make it faster. I am building a parts database for my work with listeners for filtering parts, and that might have been too slow once the database gets really big to have all the parts directly stored on the database. Your help has sent me in the right direction, thanks a million!

changing rate of Animation/Transition

I'm trying to do some basic animations, but am failing at the most simple things:
Rectangle rect = new Rectangle(100.0, 10.0);
mainPane.getChildren().add(rect); //so the rectangle is on screen
Animation anim = new Timeline(new KeyFrame(Duration.seconds(30.0),
new KeyValue(rect.widthProperty(), 0.0, Interpolator.LINEAR)));
rect.setOnMouseClicked(e -> {
if (anim.getStatus() == Status.RUNNING) {
anim.pause();
} else {
anim.setRate(Math.random() * 5.0);
anim.play();
System.out.println(anim.getRate());
}
});
The problem I am facing is that when I click the rectangle multiple times, the size will randomly jump around, instead of just changing the speed at which it drops. So for example, I let it run to about 50% size at speed ~2.5 and then stop it. When I start it up again, it will jump to a totally different size, smaller for a lower speed, bigger for a higher speed, so for example to ~20% for ~1.0 speed or ~80% for ~4.5 speed.
At first I thought animation was pre-calculated for the new speed and thus jumped to the position at which it would be, had it been played with the new speed from the beginning for the time that it was already playing before the pause, but it's bigger for a smaller speed, which doesn't really make sense then.
How do I change the speed/rate of an animation without having it jump around?
I think your diagnosis is correct: the current value is interpolated given the current time and current rate. If you decrease the rate without changing the current time, you are then earlier in the animation. Since the animation is shrinking this has the effect of making the rectangle bigger.
The easiest way is probably just to start a new animation each time:
import javafx.animation.Animation;
import javafx.animation.Animation.Status;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class VariableRateAnimation extends Application {
private Animation anim ;
#Override
public void start(Stage primaryStage) {
Pane mainPane = new Pane();
Rectangle rect = new Rectangle(100.0, 10.0);
mainPane.getChildren().add(rect); //so the rectangle is on screen
rect.setOnMouseClicked(e -> {
if (anim != null && anim.getStatus() == Status.RUNNING) {
System.out.println("Paused (" + anim.getTotalDuration().subtract(anim.getCurrentTime())+ " remaining)");
anim.pause();
} else {
Duration duration = Duration.seconds(30.0 * rect.getWidth() / (100 * Math.random() * 5.0));
System.out.println("Starting: ("+duration+ " to go)");
double currentWidth = rect.getWidth() ;
if (anim != null) {
anim.stop();
}
anim = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(rect.widthProperty(), currentWidth, Interpolator.LINEAR)),
new KeyFrame(duration, new KeyValue(rect.widthProperty(), 0.0, Interpolator.LINEAR)));
anim.play();
}
});
primaryStage.setScene(new Scene(mainPane, 600, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Can't paint an image after choosing it from JFileChooser

Good evening. I have read a lot of topics here on stackoverflow or even internet but I can't find the solution to my problem.
I have an interface like this:
When I click on "Load Image A", I can choose the image that I want. Next I want to paint this image under the JLabel "Image A". But it doesn't want to show up.
Here is the code I wrote:
package projet;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class MonPanelImage extends JPanel{
private static final long serialVersionUID = -8267224342030244581L;
private BufferedImage image;
public MonPanelImage(File adresse)
{
try{
image = ImageIO.read(adresse);
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponents(g);
System.out.println("paint");
if(image != null){
g.drawImage(image, 20, 20, this);
}
}
}
and here is where I call it:
//panel image. This is my second panel which will be for the images
final JPanel second = new JPanel(new BorderLayout());
//panel button. This is the third panel for the buttons
rows = 0;
cols = 3;
hgap = 5;
vgap = 0;
JPanel third = new JPanel(new GridLayout(rows,cols,hgap,vgap));
//buttons
JButton boutonLoad1 = new JButton("Load image A");
boutonLoad1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int retour = fc.showDialog(frame, "Charger l'image");
if(retour == JFileChooser.APPROVE_OPTION){
String pathImage1 = fc.getSelectedFile().getAbsolutePath();
path1 = pathImage1;
File file = fc.getSelectedFile();
MonPanelImage panelImage1 = new MonPanelImage(file);
second.add(panelImage1, BorderLayout.WEST);
second.revalidate();
second.repaint();
}
}
});
At the very end, i add the 3 panels to my frame and set the frame to visible.
But I can't paint an image. Maybe I'm not doing it properly. Can someone help me please?
Thanks
super.paintComponents(g);
First of all it should be super.paintComponent(g), without the "s".
second.add(panelImage1, BorderLayout.WEST);
You are adding your image to a component using a BorderLayout. The BorderLayout will respect the width of your component, which is 0, so there is nothing to paint.
Whenever, you do custom painting you need to override the getPreferredSize() method to return the size of your component so the layout manager can do its job.
However, an easier solution is to just use a JLabel with an Icon. There is no need to do custom painting when you are painting the image at its real size.

How to make a dynamic image at run time?

I'm working on a card game based on the NetBeans platform and I'm struggling to get my head around dynamic images. Why dynamic? Well I want the cards to adjust at run time to changes to the page (i.e. name, text, cost, etc).
My first hack at it was creating a component (JPanel) with labels pre-placed where I loaded the text/image based on the card values. That seems to work fine but then it became troublesome when I thought about some pages having a different look in later editions (meaning not everything would be on the same place).
So I'm trying to get an idea about ways to do this based on some kind of template.
Any idea?
There's a follow-up question at: JList of cards?
Finally I got some time to get back to this and was able to figure out a way using Java 2D tutorial.
The pictures are not near what I will use in my application but serves as proof of concept.
package javaapplication3;
import java.awt.*; 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.io.File; import java.io.IOException; import
java.net.MalformedURLException; import java.net.URL; import
java.text.AttributedCharacterIterator; import
java.text.AttributedString; import java.util.ArrayList; import
java.util.HashMap; import java.util.logging.Level; import
java.util.logging.Logger; import javax.imageio.ImageIO;
/** * * #author Javier A. Ortiz Bultrón
*/ public class DefaultImageManager {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
try {
// TODO code application logic here
DefaultImageManager manager = new DefaultImageManager();
URL url = DefaultImageManager.class.getResource("weather-rain.png");
manager.getLayers().add(ImageIO.read(url));
url = DefaultImageManager.class.getResource("weather-sun.png");
manager.getLayers().add(ImageIO.read(url));
manager.addText(new Font("Arial", Font.PLAIN, 10), "Many people believe that Vincent van Gogh painted his best works "
+ "during the two-year period he spent in Provence. Here is where he "
+ "painted The Starry Night--which some consider to be his greatest "
+ "work of all. However, as his artistic brilliance reached new "
+ "heights in Provence, his physical and mental health plummeted. ",
200, 150, new Point(0, 0));
manager.generate();
} catch (MalformedURLException ex) {
Logger.getLogger(DefaultImageManager.class.getName()).log(Level.SEVERE,
null, ex);
} catch (IOException ex) {
Logger.getLogger(DefaultImageManager.class.getName()).log(Level.SEVERE,
null, ex);
}
}
/**
* Layers used to create the final image
*/
private ArrayList layers = new ArrayList();
private ArrayList textLayers = new ArrayList();
/**
* #return the layers
*/
public ArrayList<BufferedImage> getLayers() {
return layers;
}
private Dimension getMaxSize() {
int width = 0, height = 0;
for (BufferedImage img : getLayers()) {
if (img.getWidth() > width) {
width = img.getWidth();
}
if (img.getHeight() > height) {
height = img.getHeight();
}
}
return new Dimension(width, height);
}
public void addText(Font font, String text, int height, int width, Point location) {
BufferedImage textImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
HashMap<TextAttribute, Object> map =
new HashMap<TextAttribute, Object>();
map.put(TextAttribute.FAMILY, font.getFamily());
map.put(TextAttribute.SIZE, font.getSize());
map.put(TextAttribute.FOREGROUND, Color.BLACK);
AttributedString aString = new AttributedString(text, map);
AttributedCharacterIterator paragraph = aString.getIterator();
// index of the first character in the paragraph.
int paragraphStart = paragraph.getBeginIndex();
// index of the first character after the end of the paragraph.
int paragraphEnd = paragraph.getEndIndex();
Graphics2D graphics = textImage.createGraphics();
FontRenderContext frc = graphics.getFontRenderContext();
// The LineBreakMeasurer used to line-break the paragraph.
LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, frc);
// Set break width to width of Component.
float breakWidth = width;
float drawPosY = 0;
// Set position to the index of the first character in the paragraph.
lineMeasurer.setPosition(paragraphStart);
// Get lines until the entire paragraph has been displayed.
while (lineMeasurer.getPosition() < paragraphEnd) {
// Retrieve next layout. A cleverer program would also cache
// these layouts until the component is re-sized.
TextLayout layout = lineMeasurer.nextLayout(breakWidth);
// Compute pen x position. If the paragraph is right-to-left we
// will align the TextLayouts to the right edge of the panel.
// Note: this won't occur for the English text in this sample.
// Note: drawPosX is always where the LEFT of the text is placed.
float drawPosX = layout.isLeftToRight()
? 0 : breakWidth - layout.getAdvance();
// Move y-coordinate by the ascent of the layout.
drawPosY += layout.getAscent();
// Draw the TextLayout at (drawPosX, drawPosY).
layout.draw(graphics, drawPosX, drawPosY);
// Move y-coordinate in preparation for next layout.
drawPosY += layout.getDescent() + layout.getLeading();
}
getTextLayers().add(textImage);
}
public void generate() throws IOException {
Dimension size = getMaxSize();
BufferedImage finalImage = new BufferedImage(size.width, size.height,
BufferedImage.TYPE_INT_ARGB);
for (BufferedImage img : getLayers()) {
finalImage.createGraphics().drawImage(img,
0, 0, size.width, size.height,
0, 0, img.getWidth(null),
img.getHeight(null),
null);
}
for(BufferedImage text: getTextLayers()){
finalImage.createGraphics().drawImage(text,
0, 0, text.getWidth(), text.getHeight(),
0, 0, text.getWidth(null),
text.getHeight(null),
null);
}
File outputfile = new File("saved.png");
ImageIO.write(finalImage, "png", outputfile);
}
/**
* #return the textLayers
*/
public ArrayList<BufferedImage> getTextLayers() {
return textLayers;
}
/**
* #param textLayers the textLayers to set
*/
public void setTextLayers(ArrayList<BufferedImage> textLayers) {
this.textLayers = textLayers;
} }
It still needs some refining specially on the placement of the text but it works. I guess I can implement a xml format to store all this information so is easily configurable. In the example below suns are drawn on top of rain, and the text is on top of all that. For my application each layer will build together the page I want.
Here are the images I used:
And the final result:

Resources