This discussion is archived
9 Replies Latest reply: Jan 2, 2013 5:43 AM by James_D RSS

Problem in Displaying Image

966041 Newbie
Currently Being Moderated
Hi, i am reading the pixels of the Image in fx and process it and return the processed pixels to the fx. Here the fx constructs the Image from the pixels and attach to the canvas and display in a splitpane. The whole process occurs on clicking a button.

The problem is that while displaying it some times it appears as expected and some time part of the image appears and when i click the button two to three times then the entire image appears.

Some are saying that it is due to Double Buffering Problem.
But the strange is that when i write the output image in a file then there is no problem. Problem is while displaying it.

Do i need to provide synchronization anywhere.

Even a small comment is helpful for me. Please Suggest any kind of idea that is with you.

Please help me out.
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.image.Image;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.scene.image.PixelReader;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.WritablePixelFormat;

import javafx.scene.paint.ImagePattern;
import javafx.scene.shape.Polygon;

import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.awt.Graphics;
import javax.imageio.ImageIO;
import java.io.IOException;
import javafx.scene.canvas.*;



public class Ciptk extends Application {
    
    Stage primaryStage;
    ImageView image ;
    VBox leftArea;
    HBox rightArea;
    Scene scene;
    Polygon p;
    int[] opixels;
    Image img;
    Canvas canvas;
    GraphicsContext gc;
    static int count=0,k=0;
    /**
    * @param args the command line arguments
    */
    public static void main(String[] args) {
        launch(args);
    }
    
    @Override
    public void start(Stage stage) {
        primaryStage=stage;
        primaryStage.setTitle("CIPTK");
        Group root = new Group();
        scene = new Scene(root, 350.0, 250.0);      
       
        SplitPane splitPane = new SplitPane();
        splitPane.prefWidthProperty().bind(scene.widthProperty());
        splitPane.prefHeightProperty().bind(scene.heightProperty());
        
        leftArea = new VBox(10);
        rightArea=new HBox(10);
                    
        canvas=new Canvas();
        gc = canvas.getGraphicsContext2D();

        Button negativeBut = new Button();
        negativeBut.setText("Negative");
        negativeBut.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                System.out.println("Negative Clicked");                             
                                
                int type;
                type=1;
                if(type==1)//for non-ppm image
                    img=handleImage("test.jpg");
                else
                    img=handlePPMImage("bro1.ppm");
                
                canvas.setWidth(img.getWidth());
                canvas.setHeight(img.getHeight());
                gc.drawImage(img,0,0);
                //img=null;
           
            }//handle

        });//action

        rightArea.getChildren().add(canvas);
        leftArea.getChildren().addAll(negativeBut);
        leftArea.setAlignment(Pos.BASELINE_LEFT);
        
        // add left area and right area
        splitPane.getItems().addAll(leftArea,rightArea); 
        root.getChildren().add(splitPane);
        primaryStage.setScene(scene);     
        primaryStage.show();
       
    }//start
    
    /*
        To handle the Non-PPM  image.
        
    */
     
    Image handleImage(String im){          
        Image img=new Image(im);
        //get image height ,width
        int w,h;
        h=(int)img.getHeight();
        w=(int)img.getWidth();     

        int[] pixels=new int[w*h];
        
        //get the PixelReader from Image
        PixelReader pixReader=img.getPixelReader();          
        //get the WritablePixelFormat
        WritablePixelFormat<java.nio.IntBuffer> wpixFormat=PixelFormat.getIntArgbInstance();
        //store the pixels in pixels array.
        pixReader.getPixels(0,0,w,h,wpixFormat,pixels,0,w);
     
     /*call to negativeProcessor() of ImageProcessor(a user defined java class that processes the pixels),
     pass the input pixels and receive the output pixels.
     */
     ImageProcessor imgProc=new ImageProcessor();
     opixels=imgProc.negativeProcessor(pixels,w,h);

     //create a new image from WritableImage
     WritableImage wimg=new WritableImage(w,h);
     //get the PixelWriter from WritableImage to write pixels
     PixelWriter pixWriter=wimg.getPixelWriter();                    
     //set the output pixels to the image.
     pixWriter.setPixels(0,0,w,h,wpixFormat,opixels,0,w);

        return wimg;

    }//handleImage

    //this is to handle the PPM image.

    Image handlePPMImage(String img){

        ImageProcessor imgProc=new ImageProcessor();

        BufferedImage bimage=imgProc.negativeProcessor(img,null);
     bimage.flush();
     Image image=null;
     try{
            //convert awt image to fx image.
            image=toFXImage(bimage);
        }catch(IOException io){}
        
        return image;
    }//handlePPMImage

    /*
    To convert Awt image to Fx image.   
    */
    public static javafx.scene.image.Image toFXImage(java.awt.Image image)
            throws IOException {
        if (!(image instanceof RenderedImage)) {
            BufferedImage bufferedImage = new BufferedImage(image.getWidth(null),
                    image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
            Graphics g = bufferedImage.createGraphics();
            g.drawImage(image, 0, 0, null);
            g.dispose();
            image = bufferedImage;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ImageIO.write((RenderedImage) image, "png", out);
        out.flush();
        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
        return new javafx.scene.image.Image(in);
    }//toFXImage
}//class
Edited by: 963038 on Dec 25, 2012 6:25 PM
  • 1. Re: Problem in Displaying Image
    jsmith Guru
    Currently Being Moderated
    To produce a negative image I'd do a difference blend of the image and a white rectangle.

    http://docs.oracle.com/javafx/2/api/javafx/scene/effect/BlendMode.html
    http://docs.oracle.com/javafx/2/api/javafx/scene/effect/Blend.html
    http://docs.oracle.com/javafx/2/api/javafx/scene/Node.html#setBlendMode(javafx.scene.effect.BlendMode)

    Alternatively, producing a negative using just the JavaFX pixel readers and writers and no awt is probably pretty easy.

    Also, there are routines to convert between awt and javafx images you could use if you need that, so you don't need to write your own.

    http://docs.oracle.com/javafx/2/api/javafx/embed/swing/SwingFXUtils.html

    The issue you are seeing in your code is likely threading related and caused by some error in mixing swing and javafx processing.
  • 2. Re: Problem in Displaying Image
    966041 Newbie
    Currently Being Moderated
    Thank you for your reply.
    But i don,t want to find negative only. Actually i am connecting to an old image processing library in c and getting their functionalists. If i want i can develop all the functions in java but the requirement is not like that.

    Actually i am stuck in this problem and unable to progress.
    Please help me.
  • 3. Re: Problem in Displaying Image
    James_D Guru
    Currently Being Moderated
    It actually looks as though, in this test code, you only ever invoke handleImage() and not handlePPMImage(), is that correct? In that case you never actually use your toFXImage() method. jsmith is completely correct, though, you should replace that method with a call to SwingFXUtils.toFXImage(...).

    The issues might be coming from your ImageProcessor class. Does that process the image on a background thread? If so, you may need to wait for notification that the processing is complete before updating the image. But it's hard to know without knowing how that class is set up.
  • 4. Re: Problem in Displaying Image
    966041 Newbie
    Currently Being Moderated
    Thank you james for spending some of your time on my faulty code.
    You are correct that in the above code only handleImage() is called. But in fact this is the small part of the big codes that i have taken for testing purpose.
    I didnot post all the codes as it would be very large and no one would feel good to see it. As you were talking about ImageProcessor , let me give you information regarding this.

    ImageProcessor is a java class that calls a function of NegativeProcessor.java by passing the pixel array which is acting as an interface between java and C library. The native library processes the pixels and return the out put pixel array to NegativeProcessor which forwards to ImageProcessor which in turn gives back to Test class where i would form a Javafx Image from the pixels and attach to the Canvas.

    Note:
    The native c-code creates a big array(using malloc) to store the output pixels after processing is done then returns this reference to the NegativeProcessor.java and so on...
    Do you think that the problem is with this array in the Native side ?

    Actually inside ImageProcessor if i try to write the image formed out of the pixels( received from NegativeProcessor ) in a file on a disk then there is no problem.

    So plz suggest where do i provide synchronization ? Can i call function of the ImageProcessor in separate thread and when the processing is done then transfer to the Test ?

    Please suggest with small code.

    Edited by: 963038 on Dec 26, 2012 8:38 PM
  • 5. Re: Problem in Displaying Image
    James_D Guru
    Currently Being Moderated
    It seems to me the issue is either with the ImageProcessor, or the way you're using it (e.g., it's running on a background thread and you're not waiting for it to complete correctly, or something like that). Without knowing the API for that class, I can't really help more than that.

    I wrote a naive implementation of ImageProcessor.negativeProcessor(int[], int, int) and your code works fine with this. This implementation ends up doing a lot of work on the FX Application Thread and should really be factored out into a Task, but it does seem to work and I don't see any of the issues you report.
    import java.awt.image.BufferedImage;
    
    public class ImageProcessor {
    
      public BufferedImage negativeProcessor(String img, Object ignored) {
        return null ;
      }
    
      public int[] negativeProcessor(int[] pixels, int w, int h) {
        int[] negPixels = new int[pixels.length];
        for (int i=0; i<pixels.length; i++) {
          int alpha = pixels[i] & 0xFF000000 ;
          int rgb = pixels[i] ^ 0xFFFFFF ;
          negPixels[i] = alpha |  rgb ;
        }
        return negPixels ;
      }
    
    }
    Edited by: James_D on Dec 27, 2012 2:52 PM
  • 6. Re: Problem in Displaying Image
    966041 Newbie
    Currently Being Moderated
    I am providing part of the codes of the following files with the specified functions required by my application...

    You have rightly pointed that when you process the pixels in Java files and try to display the corresponding
    image in canvas then there is no problem.(I have also tested).
    The problem is after the communication to Native codes which is in C (through JNI calls).

    Hope this would be sufficient for you to help me.


    1 ImageProcessor.java_

    Let the NonPPM (say jpg) file is handled.
    public class ImageProcessor{
        
        String img,out;
        int[] opixels;
          
        public int[] negativeProcessor(int pixels[],int iw,int ih){
            
            NegativeProcessor negativeProc = new NegativeProcessor();
            opixels=negativeProc.processNegative(pixels,iw,ih);
    
            System.out.println("ImageProcessor:Native finihed");
                 
            return opixels;
    
        }//method           
    }//class
    2. NegativeProcessor.java_
    public class NegativeProcessor{
        
       
        int[] opixels;
    
        //Native method declaration
       private native int[] negative(int[] pixelArray,int width,int height);
        
        //to load the lib dynamically.
        static{
            //there is a library with libNegativeProcessor.so in current directory.                         
            System.loadLibrary("NegativeProcessor");
        }          
    
       
        public int[] processNegative(int[] pixelArray,int width,int height){
    
       
            int opixels[]=negative(pixelArray,width,height); 
           
            System.out.println("NegativeProcessor: opixel0="+opixels[0]);
         
            return opixels;
        
        }//negativeProcessor
    
    }//class
    3._NativeProcessor.c_
    #include "ciptklib.h"
    #include "NegativeProcessor.h"
    
    int len,width,height;
    int *pixel,*opixel;
    
    int negative();
    
    
    JNIEXPORT jintArray JNICALL Java_NegativeProcessor_negative
    JNIEnv *env, jobject obj, jintArray pixelArray,jint wdth,jint hght){
        
        //get the pixel array length
        len=(*env)->GetArrayLength(env,pixelArray);
        width=wdth;height=hght;
       
        jint *arr;
        pixel=malloc(len*sizeof(int));     
        
        int i;
        
        arr=(*env)->GetIntArrayElements(env, pixelArray, NULL);
    
        //store the elements in our pixel
        for (i=0; i<len; i++) {
            pixel= arr[i]; 
    }
    //release the array
    (*env)->ReleaseIntArrayElements(env, pixelArray, arr, 0);

    negative();

    printf("Native:Negative returned\n");
    //create new intarray to store the o/p pixels from ciptk(old) and return to java
    jintArray outpixArray = (*env)->NewIntArray(env,len);
    if (outpixArray == NULL) {
    return NULL; /* out of memory error thrown */
    }
    //set the elements of int array(opixel) to jintarray(outpixArray)
    (*env)->SetIntArrayRegion(env,outpixArray ,0,len,opixel);

    free(pixel);
    free(opixel);

    printf("Native: m/o freed\n");
    //printf("Native:outpixArray=%p\n",outpixArray);

    return outpixArray;

    }//native method

    int negative(){     

    //computes the negative of the image.....
    ------------
    ------------------------

    //get the o/p pixels after computition and store there in the global opixel.
    opixel= OutPutPixels();


    return 0;

    }//negative
    There is no problem with this C file.
    All the functions are operating fine.
    
    When i receive the output pixels and form image  in above Java files and try to write 
    them in a file then the required image is formed but when i want to display it  in the 
    canvas then there is a problem.
    
    
    Please help me.
    
    Thanks for your time                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
  • 7. Re: Problem in Displaying Image
    James_D Guru
    Currently Being Moderated
    Yeah, no idea...

    I've never used JNI, so I can't really do much more. I can't see any obvious place where you're starting a background thread, and your problems sound like threading issues. I would output the width and height of the image, and the size of the arrays at all the critical steps, and see if you can figure out if, and when, the image is getting truncated.
  • 8. Re: Problem in Displaying Image
    966041 Newbie
    Currently Being Moderated
    James ,What u told sounds good.
    can u plz tell me in this program how can i use a back ground thread to display an image.
    Don't think of the JNI codes. Only look at the java code and tell me, with example code.

    I used the constructor of Image class to create an image with background option true. But that did not work for me.

    I think, if we create a new thread(of our own) that would call the functions that processes the image and when the processing is over it should inform the application thread and then only i would attach the output image to the canvas(as canvas is in the application thread).
    Please tell me how do i do this.

    I am not sure whether i am right, but hope you could understand the problem.
  • 9. Re: Problem in Displaying Image
    James_D Guru
    Currently Being Moderated
    I'm not convinced this will fix your problem, but here's a way to run the image processing on a background thread. You probably want to do this regardless of whether it fixes the issue; image processing is a time consuming task which should not be done on the Java FX Application Thread.
    import javafx.application.Application;
    import javafx.concurrent.Service;
    import javafx.concurrent.Task;
    import javafx.concurrent.WorkerStateEvent;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.geometry.Pos;
    import javafx.scene.Group;
    import javafx.scene.Scene;
    import javafx.scene.control.*;
    import javafx.scene.image.ImageView;
    import javafx.scene.image.Image;
    import javafx.scene.image.WritableImage;
    import javafx.scene.layout.HBox;
    import javafx.scene.layout.VBox;
    import javafx.stage.Stage;
    import javafx.scene.image.PixelReader;
    import javafx.scene.image.PixelWriter;
    import javafx.scene.image.PixelFormat;
    import javafx.scene.image.WritablePixelFormat;
    
    import javafx.scene.shape.Polygon;
    
    import java.awt.image.BufferedImage;
    import java.awt.image.RenderedImage;
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.awt.Graphics;
    import javax.imageio.ImageIO;
    import java.io.IOException;
    import javafx.scene.canvas.*;
    
    public class Ciptk extends Application {
    
      Stage primaryStage;
      ImageView image;
      VBox leftArea;
      HBox rightArea;
      Scene scene;
      Polygon p;
      int[] opixels;
    //  Image img;
      Canvas canvas;
      GraphicsContext gc;
      static int count = 0, k = 0;
    
      /**
       * @param args
       *          the command line arguments
       */
      public static void main(String[] args) {
        launch(args);
      }
    
      @Override
      public void start(Stage stage) {
        primaryStage = stage;
        primaryStage.setTitle("CIPTK");
        Group root = new Group();
        scene = new Scene(root, 350.0, 250.0);
    
        SplitPane splitPane = new SplitPane();
        splitPane.prefWidthProperty().bind(scene.widthProperty());
        splitPane.prefHeightProperty().bind(scene.heightProperty());
    
        leftArea = new VBox(10);
        rightArea = new HBox(10);
    
        canvas = new Canvas();
        gc = canvas.getGraphicsContext2D();
    
        // Service for computing negative images on background thread
        final Service<Image> negativeImageService = new Service<Image>() {
          @Override
          protected Task<Image> createTask() {
            // create a Task which computes negative image
            return new Task<Image>() {
              @Override
              protected Image call() throws Exception {
                int type;
                type = 1;
                Image image ;
                if (type == 1)// for non-ppm image
                  image=handleImage("test.jpg");
                else
                  image = handlePPMImage("bro1.ppm");
                return image;
              }
            };
          }
        };
        
        // Process results when service completes run
        negativeImageService.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
          @Override
          public void handle(WorkerStateEvent event) {
            Image img = negativeImageService.getValue();
            canvas.setWidth(img.getWidth());
            canvas.setHeight(img.getHeight());
            gc.drawImage(img, 0, 0);
            negativeImageService.reset();
          }
        });
        
        negativeImageService.setOnFailed(new EventHandler<WorkerStateEvent>() {
          @Override
          public void handle(WorkerStateEvent event) {
            // handle errors... just log them here but should do inform the user, etc
            System.out.println("Error occurred processing image");
            negativeImageService.getException().printStackTrace();
          }
        });
    
        Button negativeBut = new Button();
        negativeBut.setText("Negative");
        negativeBut.setOnAction(new EventHandler<ActionEvent>() {
          @Override
          public void handle(ActionEvent event) {
            System.out.println("Negative Clicked");
            negativeImageService.start();
          }// handle
    
        });// action
        
        // disable button when background process is running
        negativeBut.disableProperty().bind(negativeImageService.runningProperty());
    
        rightArea.getChildren().add(canvas);
        leftArea.getChildren().addAll(negativeBut);
        leftArea.setAlignment(Pos.BASELINE_LEFT);
    
        // add left area and right area
        splitPane.getItems().addAll(leftArea, rightArea);
        root.getChildren().add(splitPane);
        primaryStage.setScene(scene);
        primaryStage.show();
    
      }// start
    
      /*
       * To handle the Non-PPM image.
       */
    
      Image handleImage(String im) {
        Image img = new Image(im);
        // get image height ,width
        int w, h;
        h = (int) img.getHeight();
        w = (int) img.getWidth();
    
        int[] pixels = new int[w * h];
    
        // get the PixelReader from Image
        PixelReader pixReader = img.getPixelReader();
        // get the WritablePixelFormat
        WritablePixelFormat<java.nio.IntBuffer> wpixFormat = PixelFormat
            .getIntArgbInstance();
        // store the pixels in pixels array.
        pixReader.getPixels(0, 0, w, h, wpixFormat, pixels, 0, w);
    
        /*
         * call to negativeProcessor() of ImageProcessor(a user defined java class
         * that processes the pixels), pass the input pixels and receive the output
         * pixels.
         */
        ImageProcessor imgProc = new ImageProcessor();
        opixels = imgProc.negativeProcessor(pixels, w, h);
    
        // create a new image from WritableImage
        WritableImage wimg = new WritableImage(w, h);
        // get the PixelWriter from WritableImage to write pixels
        PixelWriter pixWriter = wimg.getPixelWriter();
        // set the output pixels to the image.
        pixWriter.setPixels(0, 0, w, h, wpixFormat, opixels, 0, w);
    
        return wimg;
    
      }// handleImage
    
      // this is to handle the PPM image.
    
      Image handlePPMImage(String img) {
    
        ImageProcessor imgProc = new ImageProcessor();
    
        BufferedImage bimage = imgProc.negativeProcessor(img, null);
        bimage.flush();
        Image image = null;
        try {
          // convert awt image to fx image.
          image = toFXImage(bimage);
        } catch (IOException io) {
        }
    
        return image;
      }// handlePPMImage
    
      /*
       * To convert Awt image to Fx image.
       */
      public static javafx.scene.image.Image toFXImage(java.awt.Image image)
          throws IOException {
        if (!(image instanceof RenderedImage)) {
          BufferedImage bufferedImage = new BufferedImage(image.getWidth(null),
              image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
          Graphics g = bufferedImage.createGraphics();
          g.drawImage(image, 0, 0, null);
          g.dispose();
          image = bufferedImage;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ImageIO.write((RenderedImage) image, "png", out);
        out.flush();
        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
        return new javafx.scene.image.Image(in);
      }// toFXImage
    }// class

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points