Tales of the TeenyTyper #4: A BufferedImage of a JTextPane

I’ve just gotten back to my goofery with the TeenyTyper.  I decided I wanted to log images of the editor content whenever my beloved munchkin girl hits the “clear” button, and when the application finally quits.  Turns out that getting an image of the editor’s content is easy, but you wouldn’t know it from the dead ends out there in the Interwebs that implement flawed approaches.  I’m sure someone’s done this how I describe below,  but via my web trawling it’s either buried deep or just not documented for a Web audience.

Before describing the simple answer, here’s two links leading to solutions that don’t work, along with a discussion on how each fails:

Fail #1: The Robot Approach

Here’s a link to an approach that uses Robot to capture the content of the JTextPane as an image.  Yes, Robot has a convenient createScreenCapture() method.  What happens if you’ve typed content into the editor that’s bigger than the bounds of the editor?  Sorry bub, this code can only ever captures what’s on screen.  Usability is thus too limited for my liking.

Fail #2: Selection Rectangle-mania

I coded this solution up.  It’s involved to say the least, and based on converting the cursor positions of the beginning and end points of selected text into coordinates that then gets turned into a rectangle we’ll take an image snapshot of. Once it got it working, I realised that it was limited in painful ways.  If the end cursor position is shorter in width than the widest point of selected text, the rectangle will truncate all valid text within the selection that’s beyond the end cursor point with extreme prejudice. It’s also buggy as-written, so I was thrown for a while sorting this all out (can’t quite remember what now.. I think it had something to do with a transpose() call doing crazy things).

The Win:

So.  Here it is.  All the code you need to scoop the entire content of a JTextPane out as a BufferedImage:

BufferedImage editorImage = new BufferedImage(
  textPane.getPreferredSize().width,
  textPane.getPreferredSize().height,
  BufferedImage.TYPE_INT_RGB
);

Graphics2D g = editorImage.createGraphics();

textPane.getCaret().setVisible(false);
textPane.paint(g);
textPane.getCaret().setVisible(true);

The JTextField already knows the width and height of the rectangle it needs to render without the scrollbars.  It’s exactly the rectangle of image that I want to capture. All I had to do was to paint the text pane’s content to a new Graphics2D object of the BufferedImage.  As-is, the painting is a little too literal, and will also draw in the caret.   I turn off caret visibility off briefly as I paint, and whallah!  I now have a BufferedImage that Is dead-easy to log to a PNG file  with something like:

try {
  javax.imageio.ImageIO.write(
    editorImage, 
    "png", 
    "testFile.png"
   ); 
 } catch(IOException e) { 
   System.out.println("Image save error: " + e.getMessage());
 }

I’m obsessing at the moment over how many ways this can be done (or not as the case may be).  If you’re aware of another approach, flawed or fine, leave me a comment and I’ll weave it into the story.

Live long and image capture your editor panes!

2 responses to “Tales of the TeenyTyper #4: A BufferedImage of a JTextPane

  1. I adore your wp template, exactly where do you down load it from? I want to create my own website about topics related with weight loss methods and this design really like me. Thanks for everything…

    Like

Leave a comment