RE: Using JpegXMPFrame to remotely access XMP inside JPGs over HTTP

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

RE: Using JpegXMPFrame to remotely access XMP inside JPGs over HTTP

Fergal Monaghan

Hi guys,

 

            After receiving no response from anyone else who may have encountered/solved this problem (please see below), I revisited it, had a look at Jigsaw’s source and found fixes to a few problems so that now I can HTTP Get and Put XMP into/out of JPEGs remotely. I’d like to share my finds/fixes with you guys so that they can be added to the next distribution (fixes made to Jigsaw 2.2.6): please find attached the fixed source files (4 of them) and a short readme of what changes I made and why. I’ve also included the readme inline for completeness in the mailing list archive: my fixes can be entirely replicated from Jigsaw 2.2.6 by following its steps. I hope this helps,

 

BEGIN INLINE README

=================

 

JPEG XMP fix for Jigsaw

These are fixes to some of Jigsaw's source to properly enable the HTTP Get and Put of XMP into/out of JPEG files remotely. The fixes were made on top of Jigsaw version 2.2.6.

 

Motivational problems with Jigsaw:

1. org.w3c.tools.jpeg package

            a. No writer for XMP data in JPGs

            b. No handler for XMP data in JPGs

 

2. org.w3c.jigsaw.resources.JpegFileResource class

            a. Hard-coded to use COM (comment) chunk instead of APP1 chunk (required by XMP specification)

 

3. org.w3c.jigsaw.frames.JpegXMPFrame class

            a. Does not update cache when XMP in JPG is changed

 

New files included here:

1. org.w3c.tools.jpeg.JpegXMPWriter class (to fix problem 1.a)

            Writer for XMP data in JPEGs

            a. Copied JpegCommentWriter class

            b. Replaced all references to JpegCommentWriter class with JpegXMPWriter class (to fix problem 2.a)

            c. Replaced all references to Jpeg.M_COM field with Jpeg.M_APP1 field (to fix problem 2.a)

 

2. org.w3c.tools.jpeg.JpegXMPHandler class (to fix problem 1.b)

            Handler for XMP data in JPEGs

            a. Copied JpegCommentHandler class

            b. Replaced getComment method with getXMP method:

                        public String getXMP() throws IOException,JpegException {

                                    JpegHeaders jpeghead = new JpegHeaders(in);

                                    // get the XMP out of the jpeg file

                                    return jpeghead.getXMP();

                        }

            c. Replaced all references to JpegCommentWriter class with JpegXMPwriter

 

Changes to existing files included here:

1. org.w3c.jigsaw.resources.JpegFileResource class

            a. Imported JpegXMPHandler:

                        import org.w3c.tools.jpeg.JpegXMPHandler;

            b. Added newXMPMetadataContent method (similar to newMetadataContent method: to fix problem 2.a):

            /**

             * Save the given stream as the underlying file content.

             * This method preserve the old file version in a <code>~</code> file.

             * @param in The input stream to use as the resource entity.

             * @return A boolean, <strong>true</strong> if the resource was just

             * created, <strong>false</strong> otherwise.

             * @exception IOException If dumping the content failed.

             */

 

            public synchronized boolean newXMPMetadataContent(InputStream in) throws IOException {

                        File file = getFile() ;

                        boolean created = (!file.exists() || (file.length() == 0));

                        String name = file.getName();

                        File temp = new File(file.getParent(), "#"+name+"#") ;

                        String iomsg = null ;

                        JpegXMPHandler jpegHandler = new JpegXMPHandler(file);

                        // We are not catching IO exceptions here, except to remove temp:

                        try {

                                    FileOutputStream fout  = new FileOutputStream(temp) ;

                                    char buf[] = new char[4096] ;

                                    Writer writer = jpegHandler.getOutputStreamWriter(fout);

                                    InputStreamReader reader = new InputStreamReader(in);

                                    for(int got = 0; (got = reader.read(buf)) > 0 ; )

                                                writer.write(buf, 0, got) ;

                                    writer.close() ;

                                    // Fix to ensure Windows releases lock on file...

                                    // Close and mark for garbage collection the following:

                                    // All streams, reader/writers & the JpegHandler

                                    reader.close();

                                    in.close();

                                    fout.close();

                                    reader = null;

                                    in = null;

                                    writer = null;

                                    fout = null;

                                    jpegHandler = null;

                                    // Explicitly call the Garbage Collector

                                    System.gc();

                                    // End fix for Windows

                        } catch (IOException ex) {

                                    iomsg = ex.getMessage() ;

                        } finally {

                                    if(iomsg != null) {

                                                temp.delete();

                                                throw new IOException(iomsg);

                                    }

                                    else {

                                                if(getBackupFlag()) {

                                                            File backup = getBackupFile();

                                                            if(backup.exists())

                                                            backup.delete();

                                                            file.renameTo(getBackupFile()) ;

                                                }

                                                // with some OSes, rename doesn't overwrite so...

                                                if (file.exists())

                                                            file.delete();

                                                temp.renameTo(file) ;

                                                // update our attributes for this new content:

                                                updateFileAttributes() ;

                                    }

                        }

                        return created;

            }

 

2. org.w3c.jigsaw.frames.JpegXMPFrame class

            a. Replaced all references to ImageFileResource class with JpegFileResource (so that can use newXMPMetadataContent method below)

            b. Replaced reference to ImageFileResource.newMetadataContent method with JpegFileResource.newXMPMetadataContent method (to fix problem 2.a)

            c. Added attributeChanged method (similar to JpegComFrame.attributeChanged method: to fix problem 3.a):

            /**

             * Listen its resource.

             */

            public void attributeChanged(AttributeChangedEvent evt) {

                        super.attributeChanged(evt);

                        String name = evt.getAttribute().getName();

                        if((name.equals("file-stamp")) || (name.equals("file-stamp")))

                                    xmpinfo = null;

            }

 

=================

END INLINE README

 

Fergal Monaghan

Digital Enterprise Research Institute,

Galway,

Ireland.

 


From: Monaghan, Fergal
Sent: 01 February 2008 16:11
To: [hidden email]
Subject: Using JpegXMPFrame to remotely access XMP inside JPGs over HTTP

 

Hi guys,

 

            I’ve been using JpegComFrame to access the comment block inside JPGs remotely by asking for e.g. http://sw.deri.org:8001/Photos/20071009162628.jpg;application%2frdf%2bxml

Now I want to switch over to using XMP and JpegXMPFrame: but when I run JigAdmin there isn’t the same dual MIME type options like with JpegComFrame. The only documentation I can find online on using JpegXMPFrame are single sentences like “This class will read the XMP marker from a jpeg file and return it depending on the Accept: header” [1] or “Used to extract XMP from Jpeg images.” [2] >From this I can only guess that it is not possible to simply append the desired MIME type to the end of the URL, but to create an Accept header in the HTTP request. I’ve tried the following Java in an attempt to do this programmatically, with no luck:

URL modelURL = new URL("http://sw.deri.org:8001/Photos/20080201141047.jpg");

HttpURLConnection huc = (HttpURLConnection)modelURL.openConnection();

huc.addRequestProperty("accept", "xmp");

           

            How exactly do I use the Accept: header to retrieve just the XMP metadata over HTTP? What MIME type do I need to specify? Is there any documentation anywhere that could be useful? Help!


Fergal Monaghan,

PhD Candidate,

Digital Enterprise Research Institute,

National University of Ireland, Galway,

IDA Business Park,

Lower Dangan,

Galway,

IRELAND.

 

[1] http://jigsaw.w3.org/Doc/Programmer/api/org/w3c/jigsaw/frames/JpegXMPFrame.html

[2] http://jigsaw.basemirror.de/Doc/Reference/frames.html

 


JigsawJpegXMPSource.rar (15K) Download Attachment