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

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: www-jigsaw@w3.org
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%2bxm
l

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/JpegXMPFra
me.html

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

 

Received on Monday, 31 March 2008 14:48:39 UTC