public static String writeImageToPNGFile(BufferedImage bi, File file, String comment)
        throws Exception
    {
        String warningReturn = null;

        // Get a writer than can write PNG.
        ImageWriter writer;
        {
            Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("png");
            if (!writers.hasNext()) {
                throw new RuntimeException(
                    "Unable to write PNG image because there is no registered "+
                    "image writer for that format.  That might mean the Java "+
                    "run time library is incomplete somehow.");
            }
            writer = writers.next();
        }

        try {
            // Set up the metadata structures that will allow setting
            // a text chunk comment.
            ImageWriteParam iwp = writer.getDefaultWriteParam();
            ImageTypeSpecifier its = new ImageTypeSpecifier(bi);
            IIOMetadata iiomd = writer.getDefaultImageMetadata(its, iwp);

            // Possibly add the comment.
            if (comment != null) {
                try {
                    // PNG text chunk keywords are explained at:
                    // http://www.libpng.org/pub/png/spec/iso/index-object.html#11keywords
                    addPNGTextChunk(iiomd, "Comment", comment, true /*compressed*/);
                }
                catch (Exception e) {
                    warningReturn = "Failed to add PNG text chunk comment: " +
                                    Util.getExceptionMessage(e);
                }
            }

            // Open the output file.
            OutputStream os = new BufferedOutputStream(new FileOutputStream(file));
            try {
                ImageOutputStream ios = ImageIO.createImageOutputStream(os);
                if (ios == null) {
                    throw new RuntimeException("ImageIO.createImageOutputStream(OutputStream) failed!");
                }

                try {
                    // Write the image data to that file.
                    writer.setOutput(ios);
                    writer.write(new IIOImage(bi, null, iiomd));
                }
                finally {
                    ios.close();
                }
            }
            finally {
                // You have to dig into the source code to discover this, but
                // closing 'ios' will *not* close 'os'.
                os.close();
            }
        }
        finally {
            writer.dispose();
        }

        // Double-check that reading the comment back gets the same string.
        if (comment != null && warningReturn == null) {
            String c2 = getPNGComment(file);
            if (c2 != null && comment.equals(c2)) {
                // Everything is good.
            }
            else {
                warningReturn = "PNG comment did not survive write/read cycle intact.  "+
                                "That is a bug, please report it.";
                System.err.println("Original comment: "+comment);
                System.err.println("After wr comment: "+(c2==null?"(null)":c2));
            }
        }

        return warningReturn;
    }