public XmpReaderTest()
 {
     var jpegSegments = new [] { File.ReadAllBytes("Tests/Data/withXmpAndIptc.jpg.app1.1") };
     var directories = new XmpReader().ReadJpegSegments(jpegSegments, JpegSegmentType.App1);
     _directory = directories.OfType<XmpDirectory>().ToList().Single();
     Assert.False(_directory.HasError);
 }
        /// <exception cref="System.IO.IOException"/>
        public override bool CustomProcessTag(int tagOffset, ICollection<int> processedIfdOffsets, int tiffHeaderOffset, IndexedReader reader, int tagId, int byteCount)
        {
            // Custom processing for the Makernote tag
            if (tagId == ExifDirectoryBase.TagMakernote && CurrentDirectory is ExifSubIfdDirectory)
            {
                return ProcessMakernote(tagOffset, processedIfdOffsets, tiffHeaderOffset, reader);
            }

            // Custom processing for embedded IPTC data
            if (tagId == ExifDirectoryBase.TagIptcNaa && CurrentDirectory is ExifIfd0Directory)
            {
                // NOTE Adobe sets type 4 for IPTC instead of 7
                if (reader.GetSByte(tagOffset) == 0x1c)
                {
                    var iptcBytes = reader.GetBytes(tagOffset, byteCount);
                    var iptcDirectory = new IptcReader().Extract(new SequentialByteArrayReader(iptcBytes), iptcBytes.Length);
                    iptcDirectory.Parent = CurrentDirectory;
                    Directories.Add(iptcDirectory);
                    return true;
                }
                return false;
            }

            // Custom processing for embedded XMP data
            if (tagId == ExifDirectoryBase.TagApplicationNotes && CurrentDirectory is ExifIfd0Directory)
            {
                var xmpDirectory = new XmpReader().Extract(reader.GetNullTerminatedBytes(tagOffset, byteCount));
                xmpDirectory.Parent = CurrentDirectory;
                Directories.Add(xmpDirectory);
                return true;
            }

            return false;
        }
Example #3
0
        public IEnumerable <IDocument> Execute(IReadOnlyList <IDocument> inputs, IExecutionContext context)
        {
            return(inputs.Select(x =>
            {
                MetadataExtractor.Formats.Xmp.XmpDirectory xmpDirectory;
                try
                {
                    using (var stream = x.GetStream())
                    {
                        xmpDirectory = ImageMetadataReader.ReadMetadata(stream).OfType <XmpDirectory>().FirstOrDefault();
                    }
                }
                catch (Exception)
                {
                    xmpDirectory = null;
                }
                if (xmpDirectory == null)  // Try to read sidecarfile
                {
                    if (x.ContainsKey(Keys.SourceFilePath) && System.IO.File.Exists(x[Keys.SourceFilePath] + ".xmp"))
                    {
                        string xmpXml = System.IO.File.ReadAllText(x[Keys.SourceFilePath] + ".xmp");
                        xmpDirectory = new MetadataExtractor.Formats.Xmp.XmpReader().Extract(xmpXml);
                    }
                }
                if (xmpDirectory == null)
                {
                    if (_toSearch.Any(y => y.IsMandatory))
                    {
                        context.Trace.Warning($"File doe not contain Metadata or sidecar file ({x.Source})");
                        if (_skipElementOnMissingData)
                        {
                            return null;
                        }
                    }
                    return x;
                }

                Dictionary <string, object> newValues = new Dictionary <string, object>();

                TreeDirectory hierarchicalDirectory = TreeDirectory.GetHierarchicalDirectory(xmpDirectory);

                foreach (var search in _toSearch)
                {
                    try
                    {
                        TreeDirectory metadata = hierarchicalDirectory.Childrean.FirstOrDefault(y => search.PathWithoutNamespacePrefix == y.ElementName && search.Namespace == y.ElementNameSpace);

                        if (metadata == null)
                        {
                            if (search.IsMandatory)
                            {
                                context.Trace.Error($"Metadata does not Contain {search.XmpPath} ({x.Source})");
                                if (_skipElementOnMissingData)
                                {
                                    return null;
                                }
                            }
                            continue;
                        }
                        object value = GetObjectFromMetadata(metadata, hierarchicalDirectory);
                        if (newValues.ContainsKey(search.MetadataKey) && _errorOnDoubleKeys)
                        {
                            context.Trace.Error($"This Module tries to write same Key multiple times {search.MetadataKey} ({x.Source})");
                        }
                        else
                        {
                            newValues[search.MetadataKey] = value;
                        }
                    }
                    catch (Exception e)
                    {
                        context.Trace.Error($"An exception occurred : {e} {e.Message}");
                        if (search.IsMandatory && _skipElementOnMissingData)
                        {
                            return null;
                        }
                    }
                }
                return newValues.Any() ? x.Clone(newValues) : x;
            }).Where(x => x != null));
        }
Example #4
0
        public IEnumerable<IDocument> Execute(IReadOnlyList<IDocument> inputs, IExecutionContext context)
        {
            return inputs.Select(input =>
             {
                 MetadataExtractor.Formats.Xmp.XmpDirectory xmpDirectory;
                 try
                 {
                     using (var stream = input.GetStream())
                     {

                         xmpDirectory = ImageMetadataReader.ReadMetadata(stream).OfType<XmpDirectory>().FirstOrDefault();
                     }
                 }
                 catch (Exception)
                 {
                     xmpDirectory = null;
                 }
                 if (xmpDirectory == null) // Try to read sidecarfile
                 {
                     if (input.ContainsKey(Keys.SourceFilePath) && System.IO.File.Exists(input[Keys.SourceFilePath] + ".xmp"))
                     {
                         string xmpXml = System.IO.File.ReadAllText(input[Keys.SourceFilePath] + ".xmp");
                         xmpDirectory = new MetadataExtractor.Formats.Xmp.XmpReader().Extract(xmpXml);
                     }
                 }
                 if (xmpDirectory == null)
                 {
                     if (_toSearch.Any(y => y.IsMandatory))
                     {
                         Trace.Warning($"File doe not contain Metadata or sidecar file ({input.Source})");
                         if (_skipElementOnMissingData)
                             return null;
                     }
                     return input;
                 }

                 Dictionary<string, object> newValues = new Dictionary<string, object>();

                 TreeDirectory hierarchicalDirectory = TreeDirectory.GetHierarchicalDirectory(xmpDirectory);

                 foreach (var search in _toSearch)
                 {
                     try
                     {
                         TreeDirectory metadata = hierarchicalDirectory.Childrean.FirstOrDefault(y => search.PathWithoutNamespacePrefix == y.ElementName && search.Namespace == y.ElementNameSpace);

                         if (metadata == null)
                         {
                             if (search.IsMandatory)
                             {
                                 Trace.Error($"Metadata does not Contain {search.XmpPath} ({input.Source})");
                                 if (_skipElementOnMissingData)
                                 {
                                     return null;
                                 }
                             }
                             continue;
                         }
                         object value = GetObjectFromMetadata(metadata, hierarchicalDirectory);
                         if (newValues.ContainsKey(search.MetadataKey) && _errorOnDoubleKeys)
                         {
                             Trace.Error($"This Module tries to write same Key multiple times {search.MetadataKey} ({input.Source})");
                         }
                         else
                         {
                             newValues[search.MetadataKey] = value;
                         }

                     }
                     catch (Exception e)
                     {
                         Trace.Error($"An exception occurred : {e} {e.Message}");
                         if (search.IsMandatory && _skipElementOnMissingData)
                             return null;
                     }
                 }
                 return newValues.Any() ? context.GetDocument(input, newValues) : input;
             }).Where(x => x != null);
        }
            Extract([NotNull] SequentialReader reader, int length)
        {
            var directory = new PhotoshopDirectory();

            var directories = new List<Directory> { directory };

            // Data contains a sequence of Image Resource Blocks (IRBs):
            //
            // 4 bytes - Signature; mostly "8BIM" but "PHUT", "AgHg" and "DCSR" are also found
            // 2 bytes - Resource identifier
            // String  - Pascal string, padded to make length even
            // 4 bytes - Size of resource data which follows
            // Data    - The resource data, padded to make size even
            //
            // http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_pgfId-1037504
            var pos = 0;
            while (pos < length)
            {
                try
                {
                    // 4 bytes for the signature ("8BIM", "PHUT", etc.)
                    var signature = reader.GetString(4);
                    pos += 4;

                    // 2 bytes for the resource identifier (tag type).
                    var tagType = reader.GetUInt16();
                    pos += 2;

                    // A variable number of bytes holding a pascal string (two leading bytes for length).
                    var descriptionLength = reader.GetByte();
                    pos += 1;

                    // Some basic bounds checking
                    if (descriptionLength + pos > length)
                        throw new ImageProcessingException("Invalid string length");

                    // We don't use the string value here
                    reader.Skip(descriptionLength);
                    pos += descriptionLength;

                    // The number of bytes is padded with a trailing zero, if needed, to make the size even.
                    if (pos % 2 != 0)
                    {
                        reader.Skip(1);
                        pos++;
                    }

                    // 4 bytes for the size of the resource data that follows.
                    var byteCount = reader.GetInt32();
                    pos += 4;

                    // The resource data.
                    var tagBytes = reader.GetBytes(byteCount);
                    pos += byteCount;

                    // The number of bytes is padded with a trailing zero, if needed, to make the size even.
                    if (pos % 2 != 0)
                    {
                        reader.Skip(1);
                        pos++;
                    }

                    // Skip any unsupported IRBs
                    if (signature != "8BIM")
                        continue;

                    switch (tagType)
                    {
                        case PhotoshopDirectory.TagIptc:
                            var iptcDirectory = new IptcReader().Extract(new SequentialByteArrayReader(tagBytes), tagBytes.Length);
                            iptcDirectory.Parent = directory;
                            directories.Add(iptcDirectory);
                            break;
                        case PhotoshopDirectory.TagIccProfileBytes:
                            var iccDirectory = new IccReader().Extract(new ByteArrayReader(tagBytes));
                            iccDirectory.Parent = directory;
                            directories.Add(iccDirectory);
                            break;
                        case PhotoshopDirectory.TagExifData1:
                        case PhotoshopDirectory.TagExifData3:
                            var exifDirectories = new ExifReader().Extract(new ByteArrayReader(tagBytes));
                            foreach (var exifDirectory in exifDirectories.Where(d => d.Parent == null))
                                exifDirectory.Parent = directory;
                            directories.AddRange(exifDirectories);
                            break;
                        case PhotoshopDirectory.TagXmpData:
                            var xmpDirectory = new XmpReader().Extract(tagBytes);
                            xmpDirectory.Parent = directory;
                            directories.Add(xmpDirectory);
                            break;
                        default:
                            directory.Set(tagType, tagBytes);
                            break;
                    }

                    if (tagType >= 0x0fa0 && tagType <= 0x1387)
                        PhotoshopDirectory.TagNameMap[tagType] = $"Plug-in {tagType - 0x0fa0 + 1} Data";
                }
                catch (Exception ex)
                {
                    directory.AddError(ex.Message);
                    break;
                }
            }

            return directories;
        }