Unable to draw a simple image using JComponent - image

I'm using netbeans IDE to practice some Java basic code. But I'm unsuccessful to draw a PNG image. Below is my code,
package JavaApplication1;
import javax.swing.*;
import java.awt.*;
class MyCanvas extends JComponent
{
Image img;
public MyCanvas(){
img = Toolkit.getDefaultToolkit().createImage("pengbrew.png");
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(img, 0, 0, null);
}
}
public class JavaGame
{
public static void main(String args[]){
JFrame window = new JFrame("Image demo");
window.getContentPane().add( new MyCanvas() );
window.setSize(400,400);
window.setVisible(true);
}
}
I added the images in the netbeans project.
Please advise.
Many thanks.

easiest ways is look for JLabel that's best of JComponents for Icon/ImageIcon examples here

To load an image use ImageIO.read(File file). It's a newer API, easier to use and better supported. A tutorial on loading images is here http://docs.oracle.com/javase/tutorial/2d/images/loadimage.html if you need some more pointers.
Your code would look like this instead,
Image img;
public MyCanvas(){
try {
img = ImageIO.read(new File("pengbrew.png"));
} catch (IOException e) {
// Handle exception if there is one.
}
}
For the long answer about why the method you were using wasn't working is probably because of the following...
Your image may be in the proper location and instead Toolkit.createImage() hasn't finished loading the image before the frame comes up to paint. Toolkit.createImage() returns control back to your application before the underlying image has actually finished being loaded. You can usually verify if this is the issue by resizing your application to force it to repaint. If after a few seconds of trying to resize the application the image shows up it was due to the image not being loaded during the first paint calls.
To ensure that the image is loaded before you continue you need to use a MediaTracker. Here is some example code to ensure loading of Image is complete before using it.
Component component = new Component() {};
MediaTracker TRACKER = new MediaTracker(component);
...
Image image = Toolkit.getDefaultToolkit().createImage("imageToLoad.png");
synchronized(TRACKER) {
int id = ++mediaTrackerID;
TRACKER.addImage(image, id);
try {
TRACKER.waitForID(id, 0);
} catch (InterruptedException ex) {
image = null;
}
TRACKER.removeImage(image, id);
}
// Now you can use your image.
You'll see code just like this in the ImageIcon class in the method loadImage(Image image).

Related

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!

JavaFX change the image in an imageView

Basically I have a method to load an Image from database into an imageView and a second method to change the image I'm sucessfully running both methods without getting an exception but after the setImage in changeImage() method what do I need to update and how (scene,stage) is it possible at all. I know that there is no method like repaint() in swing in javafx, so how do I approach this ?
public class MainMenuController implements Initializable {
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
private AnchorPane stck1;
#FXML
private AnchorPane openSecondWindow(ActionEvent event) throws Exception {
GUIController ctrl = new GUIController();
Stage stage = new Stage();
setStck1((AnchorPane) FXMLLoader.load(InteractiveFictionGame2.class.getResource("GUI.fxml")));
ImageView img_1 = new ImageView(ctrl.loadImg().getImage());
img_1.setPreserveRatio(true);
img_1.setSmooth(true);
img_1.setCache(true);
getStck1().getChildren().add(img_1);
Scene scene = new Scene(getStck1());
stage.setTitle("Interactive Fiction Game");
stage.setScene(scene);
stage.setFullScreen(true);
// stage.sizeToScene();
stage.show();
return getStck1();
}
public class GUIController implements Initializable {
#FXML
private TabPane tb1;
/**
* Initializes the controller class.
*
* #param url
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
#FXML
private ImageView img_1;
public ImageView loadImg() {
try {
con = DriverManager.getConnection(host, unm, pswrd);
stmnt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
rs = stmnt.executeQuery(SQL);
rs.next();
fis = rs.getBinaryStream(4);
imgt = javax.imageio.ImageIO.read(fis);
Image newImg = SwingFXUtils.toFXImage(imgt, null);
img_1 = new ImageView();
img_1.setImage(newImg);
rs.close();
stmnt.close();
con.close();
} catch (Exception e) {
System.out.println("Not working");
}
return img_1;
}
public void changeImage() {
..
fis = rs.getBinaryStream(1);
imgt = javax.imageio.ImageIO.read(fis);
Image newImg = SwingFXUtils.toFXImage(imgt, null);
img_1.setImage(newImg);
...
} catch (Exception e) {
System.out.println("Not working");
}
return img_1;
}
Your Issue
If you have a member node in your controller which you inject using #FXML, you should never create a new object instance using a new constructor and assign that new object to your existing reference. Instead just use the object which FXML created for you.
You have:
#FXML
private ImageView img_1;
That's fine.
Then in loadImg, you have:
img_1 = new ImageView();
img_1.setImage(newImg);
That is bad.
You already have an ImageView which the FXMLLoader created for you when you loaded your FXML document. The FXML Loader then assigned that ImageView to your img_1 reference because you used an #FXML annotation.
How to Fix it
So all you need to do is to stop creating new ImageViews and only write:
img_1.setImage(newImg);
And you are done.
Why it works
The Image property of ImageView is an observable property. The JavaFX system observes the Image property for any changes and if it changes, automatically updates the image displayed on the screen for the ImageView. You don't need to perform any repaint call (there is no such repaint routine to call in any case).
Background Reading
If you want to understand the JavaFX scene graph architecture better, read the Oracle tutorial on it:
Working with the JavaFX Scene Graph.
Some Tips
You can create a JavaFX image directly from an InputStream, you don't need to use ImageIO and SwingFXUtils for this task.
You can use a Task to communicate with a database and your application may be more responsive.
It is probably simpler to read the image from a file or over http rather than from a database.
Disclaimer
Besides the issue pointed out here, there may be other errors in code you have not provided which may prevent you from getting your application to work as you wish.
Java I graduate here:
In my JavaFX term project I had to update an imageView object upon a setOnAction Event (clicking a button). This allowed the program user to click through a series of pictures.
The following worked great:
First create your Image and ImageView instances:
Image imageObject = new Image();
ImageView imageViewObject = new ImageView();
Then down in the code a button event causes the (next) image to be assigned and updated as follows:
btn.setOnAction(e -> {
imageIndex++;
imageFilename = imageNamesArray.get(imageIndex);
imageObject = new Image(imageFilename);
imageViewObject.setImage(imageObject);
}
Note: The filename(s) in my project are jpg file (names) saved as String elements in an ArrayList(). The button click also increments the array index to the next jpg filename (and path or URL) and the new image would appear.
So as in the aforementioned answer you only create one ImageViewObject but you do reassign a new image to the image object "imageObject" each time.

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.

Reading Pixel values outside Processing frame

Short question: Is there a way to read RGB values of pixels on the screen, outside Processings sketch display window?
You can use's java's Robot class which has a createScreenCapture() method. This will return an image in java's most common image format: java.awt.BufferedImage.
Luckily Processing's PImage has a constructor from a java.awt.Image (including subclasses such as BufferedImage), so putting the two together is fairly straight forward:
import java.awt.*;
import java.awt.image.BufferedImage;
PImage shot;
void setup(){
rectMode(CENTER);
try
{
Robot robot = new Robot();
BufferedImage screenshot = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
shot = new PImage(screenshot);
}catch (AWTException e){
throw new RuntimeException("Unable to Initialize", e);
}
}
void draw(){
image(shot,0,0);
fill(shot.get(mouseX,mouseY));
rect(mouseX,mouseY,15,15);
}

Image processing for windows phone

im searching for a good imaging SDK for windows phone ...
i tried to use Nokia SDK but it didn't work for me, it keeps showing as exception:
"Operation Is Not Valid Due To The Current State Of The Object."
here is my test code:
The processImage method is used to apply the filter on the image.
private async void processImage()
{
WriteableBitmap writeableBitmap = new WriteableBitmap((int)bitmapImage.PixelWidth, (int)bitmapImage.PixelHeight);
try
{
using (var imageStream = new StreamImageSource(photoStream))
{
// Applying the custom filter effect to the image stream
using (var customEffect = new NegateFilter(imageStream))
{
// Rendering the resulting image to a WriteableBitmap
using (var renderer = new WriteableBitmapRenderer(customEffect, writeableBitmap))
{
// Applying the WriteableBitmap to our xaml image control
await renderer.RenderAsync();
imageGrid.Source = writeableBitmap;
}
}
}
}
catch (Exception exc) { MessageBox.Show(exc.Message + exc.StackTrace, exc.Source, MessageBoxButton.OK); }
}
This is the NegateFilter class:
namespace ImagingTest
{
class NegateFilter : CustomEffectBase
{
public NegateFilter(IImageProvider source) : base(source){}
protected override void OnProcess(PixelRegion sourcePixelRegion, PixelRegion targetPixelRegion)
{
sourcePixelRegion.ForEachRow((index, width, pos) =>
{
for (int x = 0; x < width; ++x, ++index)
{
targetPixelRegion.ImagePixels[index] = 255 - sourcePixelRegion.ImagePixels[index];
}
});
}
}
}
any ideas for a good imaging SDK? like ImageJ on java for example, or OpenCV ..
i will be better to use Nokia SDK ..
thx :)
I looked in to you code and did a quick test.
The code worked fine when I just made sure that the bitmapImage.PixelWidth and bitmapImage.PixelHeight > 0.
I did not get and image on the screen but when I remove your custom filter the image is show.
I hope you will continue to use the SDK since it is a great product.
What about emguCV?
I am not try it yet but looks like it's possible with phone's camera.

Resources