9 Replies Latest reply: Jan 2, 2013 7:43 AM by James_D RSS

    Problem in Displaying Image

    966041
      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
          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
            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
              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
                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
                  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
                    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
                      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
                        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
                          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