Solved

How to copy and print graphics

Posted on 1998-08-13
25
375 Views
Last Modified: 2013-11-23
I'm writing an app using JDK and Swing, and I'm building a set of graphic components.  I need to be able to export the picture of the completed configuration to MS apps like Word, PowerPoint, and Excel.  I also need to print this graphic.  

Ideas?  Sample code?
Thanks!
0
Comment
Question by:tsxtsx
  • 10
  • 7
  • 4
  • +1
25 Comments
 

Author Comment

by:tsxtsx
ID: 1232595
The platform is NT; the version of JDK is 1.2beta3.  The version of Swing is 1.0.2.
0
 

Expert Comment

by:awilkins
ID: 1232596
Alt-PrintScrn copies a picture of the current open window to the clipboard, which you can then paste into Word or some other place.  You can also print the image if you copy it into Microsoft Photo Editor.  Of course, the problem with this solution is that it is all manual, not automatic code.
0
 

Author Comment

by:tsxtsx
ID: 1232597
That's not really what I had in mind.  I'm looking for a way to use the clipboard and short cut keys.  The only thing I've thought of so far is to use a jni conversion routine that takes the graphic as an argument and copies it to the clipboard in binary format.  I don't even know if that's possible.  Still need help..........
0
 

Expert Comment

by:awilkins
ID: 1232598
Upon searching the documentation, I found the package com.sun.image.codec.jpeg.  Using this package, it seems to be possible to turn a BufferedImage into a jpeg file for output.  If you are double buffering your screen, you can take that BufferedImage and use it to create the JPEG from.  A sample program that draws a simple line to a file named test.jpg follows:

import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.sun.image.codec.jpeg.JPEGCodec;
import java.awt.*;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;

public class ImageOutTest extends Frame {
  BufferedImage bi;
  Graphics2D g2;
  public static void main(String args[]) {
    ImageOutTest iot = new ImageOutTest();
    iot.setSize(100, 100);
    iot.show();
  }

  public ImageOutTest() {
    bi = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
    g2 = bi.createGraphics();
    g2.draw(new Line2D.Double(50, 70, 60, 80));
    try {
      FileOutputStream jpegOut = new FileOutputStream("test.jpg");
      JPEGImageEncoder jie = JPEGCodec.createJPEGEncoder(jpegOut);
      jie.encode(bi);
    } catch (IOException e) {}
  }

  public void paint(Graphics g) {
    g2.drawImage(bi, 0, 0, 100, 100, Color.green, null);
  }
}

The problem here is that the package com.sun.image.codec.jpeg is not part of the core java platform, and, as such, is not guaranteed to be supported in future java releases.  To quote their disclaimer:

Note that the classes in the com.sun.image.codec.jpeg package are not part of the core Java APIs. They are a part of Sun's JDK and JRE distributions. Although other licensees may choose to distribute these classes, developers cannot depend on their availability in non-Sun implementations. We expect that equivalent functionality will eventually be available in a core API or standard extension.

However, this will code the image into a portable format, suitable for use in other programs.
0
 

Expert Comment

by:awilkins
ID: 1232599
Oops -- you also need to import java.io.IOException.  Otherwise, the code compiles.
0
 

Expert Comment

by:rick1
ID: 1232600
tsxtsx,

I have this same requirements for an application that I'm working on.  I've decided to use the JNI for system clipboard access.  I'm currently working on some proof-of-concept code, and would be glad to share information as my process progresses.

0
 
LVL 2

Accepted Solution

by:
threshold earned 200 total points
ID: 1232601
In Applet, you need to make the applet signed , then you can access PrintJob and Clipboard.
You can find docs about signed applet and Capability from www.netscape.com.
In NS, you can get the rights of accessing of PrintJob anc Clipboard via code below.
    PrivilegeManager.enablePrivilege("UniversalSystemClipboardAccess");
    PrivilegeManager.enablePrivilege("UniversalPrintJobAccess");

In Signed Applet and application, to print image is very simple.
Just paint the Image on a canvas or any AWT component, then call the printAll(Graphics) method.
example:
  PrintJob pjob = getToolkit().getPrintJob(new Frame(),"Printing Test", null); // get printjob
  Graphics pg = pjob.getGraphics(); // get the Graphics
  mycanvas.paintAll(pg);  //paint the canvas on the Graphics of PrintJob

To copy the image is more difficult, you should to understand how to use the java clipboard and java.awt.datatransfer
1. encode your image into Bitmap bytes and get the ByteArrayInputStream. (not easy, you will need the spec of .BMP format)
2. create DataFlaver for BMP file
       bmpFlavor = new DataFlavor("image/bmp", "BMP file");

3. create your BMPSelection that implements Transferable, ClipboardOwner

      public class BMPSelection implements Transferable, ClipboardOwner{
        DataFlavor flavors[] = {new DataFlavor("image/bmp", "BMP file")};
        private InputStream is;
        public BMPSelection(InputStream is) {
          this.is = is;
        }
        public synchronized Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
          if (flavor.equals(flavors[0])) {
           return is;
         } else {
            throw new UnsupportedFlavorException(flavor);
         }
       }
       public synchronized DataFlavor[] getTransferDataFlavors() {
         return flavors;
       }
       public boolean isDataFlavorSupported(DataFlavor flavor) {
         return (flavor.equals(flavors[0]));
       }
       public void lostOwnership(Clipboard clipboard, Transferable contents) {
       }
     }

4. get the Clipboard and use it

    byte[] encodeBMP (Image img) {
        ImageProducer ip=img.getSource();
        ...... // get the bytes of BMP
        return bytes
    }
    void copyToClipboard (Image img) {
        Clipboard cb=Toolkit.getDefaultToolkit().getSystemClipboard();
        BMPSelection contents = new BMPSelection(encodeBMP(img));
        cb.setContents(contents, this);
    }
    void pasteFromClipboard() {
       Clipboard cb=Toolkit.getDefaultToolkit().getSystemClipboard();
       Transferable content = cb.getContents(this); // now you can get content from Clipboard
       DataFlavor[] flavors=content.getTransferDataFlavors(); // then you can get the flavors
       for (int i=0;i<flavors.length;i++) {
          if (flavors[i].getMimeType().equalsIgnoreCase("image/bmp")) {
             InputStream is=(InputStream)content.getTransferData(flavorsp[i]);
             // read the data from inputstream
             // transfer the BMP data into image and show it
          }
      }
   }

Here, you can use the JPEG or GIF, too, if you can get the decoder/encoder of JPEG or GIF.
I am sure that you can find the decoder/encoder of BMP,JPEG,GIF on net.
If you can't find those, I suggest to write your BMPEncoder/BMPDecoder, it's more easy than JPEG and GIF.

0
 
LVL 2

Expert Comment

by:threshold
ID: 1232602
sorry, there should be "mycanvas.printAll(pg);", and call the pjob.end() after that.

I haven't try the code. If it works or not, please post a comment for me.
0
 
LVL 2

Expert Comment

by:threshold
ID: 1232603
BTW, awlkins...
   Where can I find the package 'com.sun.image.codec.jpeg.*' ?
0
 

Author Comment

by:tsxtsx
ID: 1232604
This doesn't have to be in an Applet, correct?
0
 

Expert Comment

by:awilkins
ID: 1232605
com.sun.image.codec.jpeg.* is one of the non-core packages in the jdk 1.2beta4.
0
 

Expert Comment

by:rick1
ID: 1232606
Comments regarding the answer given by threshold.  Maybe I don't understand the whole solution, but aren't you creating a mime type,serializing a bitstream into it, and copying the mime type to the system clipboard as a string ??
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 2

Expert Comment

by:threshold
ID: 1232607
tsxtsx,
   you r right, it donesn't have to be in an applet. I mean that, in Applet, you have to signed the applet before you use the clipboard or printjob. In applications, you can access clipboard and printjob directly.

awilkins,
   thanks, i will find it in JDK 1.2.

rick,
   In JDK1.1.x, the Clipboard can recieve Object, not only String or InputStream. But if we want the Application can communicate with non-java program via Clipboard, we should use MIME. If we make the Java applications can exchange something in Clipboard, we 'may' use Java Object.
   With MIME, an Application want to get data from Clipboard, there are several things will happen:
   1. The Application will check which MIME types can be supported by the data. DataFlavor[] Transferable.getTransferDataFlavors() should provide this information.
   2. Then, Application will see, is there any MIME type can be used by it?
   3. If true, Application require the data with the MIME type name. The Clipboard redirect the request to Java Application.
   4. Java Application encode the data , the data format depends on the MIME type name in the request.
   5. Java Application return the InputStream that contains the data.
   6. Clipboard recieve the data and return it to Application

Hope it's useful for you.
0
 

Expert Comment

by:rick1
ID: 1232608
Threshold
I understand that objects can be serialized to the clipboard. It is also my understanding that java only supports copying string types to the system clipboard. So, typically anything copied from
java must be MIME or string.  So, even if you copy a BMP as MIME to the SYSTEM clipboard an application like word will not be able to interpret the data.  Am I wrong here ??  
0
 

Author Comment

by:tsxtsx
ID: 1232609
threshold,

I had the same understanding as rick1.  If I copy something in my Java app to the clipboard in MIME format, I can't paste it into MS Word.  Is that right?  That is the thrust of my original question.


0
 
LVL 2

Expert Comment

by:threshold
ID: 1232610
When you paste the Image data into MS Word, the MS Word will send the request to Clipboard to get the MIME types supported by current data. Then MS Word decide which MIME type is preferred. Then, MS Word send the request with the MIME type, and the Clipboard have to send the data formatted with the MIME type back to Word.

If there is no suitable MIME type for Word, the 'paste' action will be cancelled.

So, we should let our data can support as many MIME types as possible.

By Ms Office, the preferred mime type of image is BMP. For this, we should let our Image data can support 'image/bmp'.

Clipboard in Java can support MIME and Java Class(including String). If you want two Java programs communicate with each other, we may use the Java Class as DataFlavor. But we want Java Program can communicate with non-java program, we should use the MIME DataFlavor. For example, we want the notepad can recieve String from Java via clipboard, the Transferrable Object should support 'text/plain', not only String.

To use MIME DataFlavor, we need the Transferrable Object can provide an InputStream that contains formatted data.


0
 
LVL 2

Expert Comment

by:threshold
ID: 1232611
BTW... If you choose to use Java Class as DataFlavor, the Java Class needn't implement Serializable Interface.
Because, only the Java program in same VM can get it, ie, the Object will not be transferred through Window System Clipboard.It is just stored in Java Clipboard.
0
 
LVL 2

Expert Comment

by:threshold
ID: 1232612
Here is my explanation:

As Java Program, I am the data factory. One day, I told to the Market (Clipboard) that I provide something. The Market manager post a note on the wall of office. (the wall is very small, it can contain only one note on it).

As Word, You walk to the Market, you find the note on the wall. You are interested by it. So, you ask the Market manager "Which formats are supported by the stuff?". The manager says : "Wait a minute, I ask the provider for you...".

Then, the manager call me, I told him "My Object support GIF and BMP". When you receive my answer from manager, you say "Oh, BMP is fine, please".

The Market manager tell me the preferable format. My factory start to work and build the data with the format, then send it to the Market. And then, you get the data from the Market.

I mean, my data haven't be generated when I post the note to market.
0
 

Expert Comment

by:rick1
ID: 1232613
Threshold
This sounds like a good platform independent solution if it works.  It would be my preference to use your solution if possible. However,  I looked up the image formats supported by MS Word and MIME was not among them.  Have you gotten this solution to work?  If so, do you have some code ??  I'm very curious to see the whole solution. Thanks
0
 

Expert Comment

by:rick1
ID: 1232614
TSXTSX
The following solution works but its not platform independent.
I use the JNI to a dll which copies the bits to the clipboard.
This was just a proof-of-concept.  There may be other BMP format
considerations.  This solution needs to be refined but the general functionality is correct.

void jButton3_actionPerformed(ActionEvent e) {

 Image img = jPanel1.img;
 int width = img.getWidth(jPanel1);
 int height = img.getHeight(jPanel1);

 int[] pixels = new int[width * height];
 PixelGrabber pg = new PixelGrabber(img, 0, 0, width,height,pixels, 0, width);

 try {
     pg.grabPixels();
 } catch (InterruptedException ev) {
   System.err.println("interrupted waiting for pixels!");
   return;
 }

 if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
    System.err.println("image fetch aborted or errored");
    return;
 }

 if ((pg.getStatus() & ImageObserver.ALLBITS ) != 0 ){
    System.out.println("pixelsize=" +pg.getColorModel ().getPixelSize());
   // No is a class member, An instance of NativeObj
   No.copyImageToSystem(width,height,(int[])pg.getPixels());
 }
}// end function

/**** NATIVE CLASS ****/

public class NativeObj{

  NativeObj(){
  }

  static{
    System.out.println("loading library");
    System.loadLibrary("jnitest");
  }

  public native static void copyImageToSystem( int width, int height, int pixels[] );

  public native static void simpleNativeCall();

}

/*** DLL FUNCTION ****/

JNIEXPORT void JNICALL Java_testapp_NativeObj_copyImageToSystem
  (JNIEnv * jni, jclass t, jint w, jint h, jintArray bytes )
{
      BOOL bOk = false;

      HWND hWnd = GetDesktopWindow();


      HDC dc = GetDC( hWnd );

      int planes = GetDeviceCaps( dc,PLANES );
      int btspixel = GetDeviceCaps( dc,BITSPIXEL );

            
      HBITMAP hBmp = CreateCompatibleBitmap( dc,w,h );
      if ( hBmp )
      {
            jint  len = jni->GetArrayLength( bytes );
            jint * bits = jni->GetIntArrayElements( bytes,0 );

            char out[30];
            sprintf(out,"size = %ld",len);
            MessageBox( hWnd,out,"CAPTION",MB_OK);

            if ( !SetBitmapBits( hBmp,sizeof(jint)*len,bits ) )
            {
            // error
                  
                  MessageBox( hWnd,"ERROR","CAPTION",MB_OK);
                  return;
            }

            bOk = true;
      }


      ReleaseDC( hWnd,dc );


      if ( bOk )
      {
            bOk = false;

            if (OpenClipboard( hWnd) )
            {
                  EmptyClipboard();

                  if ( SetClipboardData( CF_BITMAP,hBmp ) )
                  {
                        bOk= true;
                  }
                  else
                  {
                  }

                  CloseClipboard();
            }
            else
            {
            }
      }
}
0
 
LVL 2

Expert Comment

by:threshold
ID: 1232615
rick1
I have no Encoder/Decoder of BMP,JPEG,GIF here.
I think there are some usable free ones on net.
If I can't find it, I will create it, 'cause the BMP and GIF encoder is easy to build.

I have create a HTMLSelection with text/plain(created by sun) and text/html(created by me), it works fine.
So, I think this solution will work for binary data.

Here is My HTMLSelection
            public class HTMLSelection implements Transferable, ClipboardOwner{
                static DataFlavor HTMLFlavor=new new DataFlavor("text/plain", "HTML");
                DataFlavor flavors[] = {HTMLFlavor,DataFlavor.plainTextFlavor};
                private String doc;
                public HTMLSelection(String htmlDoc) {
                  this.doc = htmlDoc;
                }
                public synchronized Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
                  if (flavor.equals(flavors[0])) {
                   return new StringReader(doc);
                 } else if (flavor.equals(flavors[1])) {
                   String plainText="";
                   ...... // remove all HTML tags <....> from doc and store it into plainText
                   return new StringReader(plainText);
                 } else {
                    throw new UnsupportedFlavorException(flavor);
                 }
               }
               public synchronized DataFlavor[] getTransferDataFlavors() {
                 return flavors;
               }
               public boolean isDataFlavorSupported(DataFlavor flavor) {
                 return (flavor.equals(flavors[0]) || flavor.equals(flavors[1]));
               }
               public void lostOwnership(Clipboard clipboard, Transferable contents) {
               }
             }
0
 

Expert Comment

by:rick1
ID: 1232616
threshold
I've written the same code for text data transfer.  I'm more interested in your binary solution, to see if MS Word will recognize a MIME format. Thanks in advance
0
 
LVL 2

Expert Comment

by:threshold
ID: 1232617
I found a URL http://www.acme.com/java/software/
There is a GIF Encoder, but , i am not sure if MS Word can support GIF or not.

public class GIFSelection implements Transferable, ClipboardOwner{
  DataFlavor flavors[] = {new DataFlavor("image/gif", "GIF")};
  private Image img;
  public GIFSelection(Image img) {
    this.img = img;
  }
  public synchronized Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
    if (flavor.equals(flavors[0])) {
       ByteArrayOutputStream os=new ByteArrayOutputStream();
       Acme.JPM.Encoders.GifEncoder encoder=new Acme.JPM.Encoders.GifEncoder(img,os);
       ByteArrayInputStream is=new ByteArrayInputStream(os.toByteArray());
       return is;
    } else {
       throw new UnsupportedFlavorException(flavor);
    }
 }
 public synchronized DataFlavor[] getTransferDataFlavors() {
   return flavors;
 }
 public boolean isDataFlavorSupported(DataFlavor flavor) {
    return (flavor.equals(flavors[0]));
 }
 public void lostOwnership(Clipboard clipboard, Transferable contents) {
   }
}
0
 
LVL 2

Expert Comment

by:threshold
ID: 1232618
tsxtsx:
    Can it work? please give me a reply...
0
 

Expert Comment

by:rick1
ID: 1232619
tsxtsx,

Did you get the bmp solution to work with the system clipboard?  What where the issues with the encode/decoder for the bmp ?
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

By the end of 1980s, object oriented programming using languages like C++, Simula69 and ObjectPascal gained momentum. It looked like programmers finally found the perfect language. C++ successfully combined the object oriented principles of Simula w…
I've been using this technique since Adobe CS2, and it should work with any version of Illustrator that includes the appearance panel. In this tutorial we'll create a button using the appearance panel in Adobe Illustrator, and then save it as a r…
Viewers will learn how to properly install Eclipse with the necessary JDK, and will take a look at an introductory Java program. Download Eclipse installation zip file: Extract files from zip file: Download and install JDK 8: Open Eclipse and …
Learn how to download your full Prezi presentation for offline presenting. Prezi doesn’t have to be viewed and shared in a web browser, even with a free account you can download your full presentation to share with others. Be sure to download any vi…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now