public String getXmpXml(ByteSource byteSource, Map params)
            throws ImageReadException, IOException
    {

        final List result = new ArrayList();

        JpegUtils.Visitor visitor = new JpegUtils.Visitor() {
            // return false to exit before reading image data.
            public boolean beginSOS()
            {
                return false;
            }

            public void visitSOS(int marker, byte markerBytes[],
                    byte imageData[])
            {
            }

            // return false to exit traversal.
            public boolean visitSegment(int marker, byte markerBytes[],
                    int markerLength, byte markerLengthBytes[],
                    byte segmentData[]) throws ImageReadException, IOException
            {
                if (marker == 0xffd9)
                    return false;

                if (marker == JPEG_APP1_Marker)
                {
                    if (new JpegXmpParser().isXmpJpegSegment(segmentData))
                    {
                        result.add(new JpegXmpParser()
                                .parseXmpJpegSegment(segmentData));
                        return false;
                    }
                }

                return true;
            }
        };
        new JpegUtils().traverseJFIF(byteSource, visitor);

        if (result.size() < 1)
            return null;
        if (result.size() > 1)
            throw new ImageReadException(
                    "Jpeg file contains more than one XMP segment.");
        return (String) result.get(0);
    }