public DirectoryList ReadJpegSegments(IEnumerable <JpegSegment> segments)
        {
            // Ensure collection materialised (avoiding multiple lazy enumeration)
            segments = segments.ToList();

            var directories = segments
                              .Where(IsXmpSegment)
                              .Select(segment => Extract(segment.Bytes, JpegSegmentPreambleBytes.Length, segment.Bytes.Length - JpegSegmentPreambleBytes.Length))
                              .Cast <Directory>()
                              .ToList();

            var extensionGroups = segments.Where(IsExtendedXmpSegment).GroupBy(GetExtendedDataGuid);

            foreach (var extensionGroup in extensionGroups)
            {
                var buffer = new MemoryStream();
                foreach (var segment in extensionGroup)
                {
                    var N = JpegSegmentPreambleExtensionBytes.Length + 32 + 4 + 4;
                    buffer.Write(segment.Bytes, N, segment.Bytes.Length - N);
                }

                buffer.Position = 0;
                var directory = new XmpDirectory();
                var xmpMeta   = XmpMetaFactory.Parse(buffer);
                directory.SetXmpMeta(xmpMeta);
                directories.Add(directory);
            }

            return(directories);
        }
Пример #2
0
        /**
         * Adds information about the PDF/A conformance level to the XMP metadata.
         *
         * @param conformanceLevel
         * @throws IOException
         */
        private void AddRdfDescription(PdfAConformanceLevel conformanceLevel)
        {
            switch (conformanceLevel)
            {
            case PdfAConformanceLevel.PDF_A_1A:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "1");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "A");
                break;

            case PdfAConformanceLevel.PDF_A_1B:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "1");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "B");
                break;

            case PdfAConformanceLevel.PDF_A_2A:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "2");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "A");
                break;

            case PdfAConformanceLevel.PDF_A_2B:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "2");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "B");
                break;

            case PdfAConformanceLevel.PDF_A_2U:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "2");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "U");
                break;

            case PdfAConformanceLevel.PDF_A_3A:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "3");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "A");
                break;

            case PdfAConformanceLevel.PDF_A_3B:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "3");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "B");
                break;

            case PdfAConformanceLevel.PDF_A_3U:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "3");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "U");
                break;

            case PdfAConformanceLevel.ZUGFeRD:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "3");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "B");
                IXmpMeta taggedExtensionMeta = XmpMetaFactory.ParseFromString(zugferdExtension);
                XmpUtils.AppendProperties(taggedExtensionMeta, xmpMeta, true, false);
                break;

            default:
                break;
            }
            if (writer.IsTagged())
            {
                IXmpMeta taggedExtensionMeta = XmpMetaFactory.ParseFromString(pdfUaExtension);
                XmpUtils.AppendProperties(taggedExtensionMeta, xmpMeta, true, false);
            }
        }
Пример #3
0
        public void copyDateCreatedToDateTimeOriginal()
        {
            IXmpMeta xmpMeta;

            using (var fileStream = File.OpenRead(XmpFile.FullName))
            {
                xmpMeta = XmpMetaFactory.Parse(fileStream);
                if (xmpMeta.DoesPropertyExist("http://ns.adobe.com/photoshop/1.0/", "photoshop:DateCreated"))
                {
                    IXmpDateTime    xmpMetaCreateDate       = xmpMeta.GetPropertyDate("http://ns.adobe.com/photoshop/1.0/", "photoshop:DateCreated");
                    List <FileInfo> correspondingImageFiles = this.getCorrespondingImageFile();
                    foreach (FileInfo correspondingImageFile in correspondingImageFiles)
                    {
                        DateTime?DateTimeOriginal = this.getDateTimeOriginal(correspondingImageFile);
                        if (DateTimeOriginal == null)
                        {
                            ExifToolWrapper  exifTool           = new ExifToolWrapper();
                            ExifToolResponse jsonExifToolOutput = exifTool.execute(string.Concat("-m -S -overwrite_original \"-DateTimeOriginal=", xmpMetaCreateDate.ToIso8601String(), "\""), correspondingImageFile);
                        }
                        else
                        {
                            Program.MainLogger.Information($"DateTimeOriginal TAG in file {correspondingImageFile} already set to {DateTimeOriginal}");
                        }
                    }
                }
                else
                {
                    Program.MainLogger.Information($"Cant't find 'photoshop:DateCreated' property in namespace 'http://ns.adobe.com/photoshop/1.0/'");
                }
            }
        }
Пример #4
0
        /**
         * Test simple constructors and parsing, setting the instance ID
         * @throws XmpException Forwards exceptions
         */
        private static void CoverCreatingXmp()
        {
            writeMajorLabel("Test simple constructors and parsing, setting the instance ID");

            var meta1 = XmpMetaFactory.Create();

            printXmpMeta(meta1, "Empty XMP object");

            var meta2 = XmpMetaFactory.Create();

            meta2.SetObjectName("New object name");
            printXmpMeta(meta2, "XMP object with name");

            var meta3 = XmpMetaFactory.ParseFromString(TestData.RDF_COVERAGE);

            printXmpMeta(meta3, "Construct and parse from buffer");

            meta3.SetProperty(XmpConstants.NsXmpMm, "InstanceID", "meta2:Original");
            printXmpMeta(meta3, "Add instance ID");

            XmpMeta meta4 = (XmpMeta)meta3.Clone();

            meta4.SetProperty(XmpConstants.NsXmpMm, "InstanceID", "meta2:Clone");
            printXmpMeta(meta3, "Clone and add instance ID");
        }
Пример #5
0
        public void BillionLaughs_DoctypeDisabled()
        {
            var testdata = @"<?xml version=""1.0""?>
                <!DOCTYPE lolz [
                <!ENTITY lol ""lol"">
                <!ENTITY lol2 ""&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"">
                <!ENTITY lol3 ""&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"">
                <!ENTITY lol4 ""&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"">
                <!ENTITY lol5 ""&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"">
                <!ENTITY lol6 ""&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"">
                <!ENTITY lol7 ""&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"">
                <!ENTITY lol8 ""&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"">
                <!ENTITY lol9 ""&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"">
                ]>
                <lolz>&lol9;</lolz>";

            XmpException e = null;

            try
            {
                // doctype not allowed by default
                XmpMetaFactory.ParseFromString(testdata);
            }
            catch (XmpException ex)
            {
                e = ex;
            }

            Assert.NotNull(e);
            Assert.True(e.InnerException.Message.StartsWith("For security reasons DTD is prohibited"));
        }
Пример #6
0
        public void BillionLaughs_DoctypeEnabled()
        {
            var testdata = @"<?xml version=""1.0""?>
                <!DOCTYPE lolz [
                <!ENTITY lol ""lol"">
                <!ENTITY lol2 ""&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"">
                <!ENTITY lol3 ""&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"">
                <!ENTITY lol4 ""&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"">
                <!ENTITY lol5 ""&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"">
                <!ENTITY lol6 ""&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"">
                <!ENTITY lol7 ""&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"">
                <!ENTITY lol8 ""&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"">
                <!ENTITY lol9 ""&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"">
                ]>
                <lolz>&lol9;</lolz>";

            var options = new Options.ParseOptions();

            // enable doctype
            options.DisallowDoctype = false;

            XmpException e = null;

            try
            {
                XmpMetaFactory.ParseFromString(testdata, options);
            }
            catch (XmpException ex)
            {
                e = ex;
            }

            Assert.NotNull(e);
            Assert.True(e.InnerException.Message.StartsWith("The input document has exceeded a limit set by MaxCharactersFromEntities"));
        }
Пример #7
0
        public void XXE_DoctypeDisabled()
        {
            string testdata = @"<!DOCTYPE doc [<!ENTITY win SYSTEM ""c:\windows\win.ini"">]><doc></doc>";

            // doctype not allowed by default
            Assert.Throws <XmpException>(() => XmpMetaFactory.ParseFromString(testdata));
        }
Пример #8
0
        /**
         * Parse and serialize methods.
         * @throws XmpException Forwards exceptions
         */
        private static void CoverParsing()
        {
            writeMajorLabel("Test parsing with multiple buffers and various options");

            var meta = XmpMetaFactory.ParseFromString(TestData.SIMPLE_RDF);

            printXmpMeta(meta, "Parse from String");

            meta = XmpMetaFactory.ParseFromString(TestData.SIMPLE_RDF, new ParseOptions {
                RequireXmpMeta = true
            });
            printXmpMeta(meta, "Parse and require xmpmeta element, which is missing");

            meta = XmpMetaFactory.ParseFromString(TestData.NAMESPACE_RDF);
            printXmpMeta(meta, "Parse RDF with multiple nested namespaces");

            meta = XmpMetaFactory.ParseFromString(TestData.XMPMETA_RDF, new ParseOptions {
                RequireXmpMeta = true
            });
            printXmpMeta(meta, "Parse and require xmpmeta element, which is present");

            meta = XmpMetaFactory.ParseFromString(TestData.INCONSISTENT_RDF);
            printXmpMeta(meta, "Parse and reconcile inconsistent aliases");

            try
            {
                XmpMetaFactory.ParseFromString(TestData.INCONSISTENT_RDF, new ParseOptions {
                    StrictAliasing = true
                });
            }
            catch (XmpException e)
            {
                log.WriteLine("Parse and do not reconcile inconsistent aliases - threw XmpException #{0} :   {1}", e.GetErrorCode(), e.Message);
            }
        }
Пример #9
0
        public FileIndexItem GetDataFromString(string xmpDataAsString, FileIndexItem databaseItem = null)
        {
            // Does not require appSettings

            if (databaseItem == null)
            {
                databaseItem = new FileIndexItem();
            }

            try
            {
                var xmp = XmpMetaFactory.ParseFromString(xmpDataAsString);
                // ContentNameSpace is for example : Namespace=http://...
                databaseItem = GetDataContentNameSpaceTypes(xmp, databaseItem);
                // NullNameSpace is for example : string.Empty
                databaseItem = GetDataNullNameSpaceTypes(xmp, databaseItem);
            }
            catch (XmpException e)
            {
                Console.WriteLine($"XmpException {databaseItem.FilePath} >>\n{e}\n <<XmpException");
                databaseItem.Tags       = "XmpException";
                databaseItem.ColorClass = ColorClassParser.Color.None;
            }


            return(databaseItem);
        }
Пример #10
0
        /**
         * Test CR and LF in values.
         * @throws XmpException Forwards exceptions
         */
        private static void CoverLinefeedValues()
        {
            writeMajorLabel("Test CR and LF in values");

            string valueWithCR   = "ASCII \r CR";
            string valueWithLF   = "ASCII \n LF";
            string valueWithCRLF = "ASCII \r\n CRLF";

            var meta = XmpMetaFactory.ParseFromString(TestData.NEWLINE_RDF);

            meta.SetProperty(TestData.NS2, "HasCR", valueWithCR);
            meta.SetProperty(TestData.NS2, "HasLF", valueWithLF);
            meta.SetProperty(TestData.NS2, "HasCRLF", valueWithCRLF);

            string result = XmpMetaFactory.SerializeToString(meta, new SerializeOptions {
                OmitPacketWrapper = true
            });

            log.WriteLine(result);

            var hasCR    = meta.GetPropertyString(TestData.NS1, "HasCR");
            var hasCR2   = meta.GetPropertyString(TestData.NS2, "HasCR");
            var hasLF    = meta.GetPropertyString(TestData.NS1, "HasLF");
            var hasLF2   = meta.GetPropertyString(TestData.NS2, "HasLF");
            var hasCRLF  = meta.GetPropertyString(TestData.NS1, "HasCRLF");
            var hasCRLF2 = meta.GetPropertyString(TestData.NS2, "HasCRLF");

            if (hasCR == valueWithCR && hasCR2 == valueWithCR &&
                hasLF == valueWithLF && hasLF2 == valueWithLF &&
                hasCRLF == valueWithCRLF && hasCRLF2 == valueWithCRLF)
            {
                log.WriteLine();
                log.WriteLine("\n## HasCR and HasLF and HasCRLF correctly retrieved\n");
            }
        }
Пример #11
0
        /// <summary>
        /// Some image editing apps such as Lightroom, On1, etc., do not persist the keyword metadata
        /// in the images by default. This can mean you keyword-tag them, but those keywords are only
        /// stored in the sidecars. Damselfly only scans keyword metadata from the EXIF image data
        /// itself.
        /// So to rectify this, we can either read the sidecar files for those keywords, and optionally
        /// write the missing keywords to the Exif Metadata as we index them.
        /// </summary>
        /// <param name="img"></param>
        /// <param name="keywords"></param>
        private void ProcessSideCarKeywords(Image img, string[] keywords)
        {
            var sideCarTags = new List <string>();

            var           sidecarSearch = Path.ChangeExtension(img.FileName, "*");
            DirectoryInfo dir           = new DirectoryInfo(img.Folder.Path);
            var           files         = dir.GetFiles(sidecarSearch);

            var on1Sidecar = files.FirstOrDefault(x => x.Extension.Equals(".on1", StringComparison.OrdinalIgnoreCase));

            if (on1Sidecar != null)
            {
                var on1MetaData = On1Sidecar.LoadMetadata(on1Sidecar);

                if (on1MetaData != null)
                {
                    var missingKeywords = on1MetaData.Keywords
                                          .Except(keywords, StringComparer.OrdinalIgnoreCase)
                                          .ToList();

                    if (missingKeywords.Any())
                    {
                        Logging.LogVerbose($"Image {img.FileName} is missing {missingKeywords.Count} keywords present in the On1 Sidecar.");
                        sideCarTags = sideCarTags.Union(missingKeywords, StringComparer.OrdinalIgnoreCase).ToList();
                    }
                }
            }

            var xmpSidecar = files.FirstOrDefault(x => x.Extension.Equals(".xmp", StringComparison.OrdinalIgnoreCase));

            if (xmpSidecar != null)
            {
                using var stream = File.OpenRead(xmpSidecar.FullName);
                IXmpMeta xmp = XmpMetaFactory.Parse(stream);

                var xmpKeywords = xmp.Properties.FirstOrDefault(x => x.Path == "pdf:Keywords");

                if (xmpKeywords != null)
                {
                    var missingKeywords = xmpKeywords.Value
                                          .Split(",")
                                          .Select(x => x.Trim())
                                          .Except(keywords)
                                          .ToList();

                    if (missingKeywords.Any())
                    {
                        Logging.LogVerbose($"Image {img.FileName} is missing {missingKeywords.Count} keywords present in the XMP Sidecar.");
                        sideCarTags = sideCarTags.Union(missingKeywords, StringComparer.OrdinalIgnoreCase).ToList();
                    }
                }
            }

            if (sideCarTags.Any())
            {
                // Now, submit the tags; note they won't get created immediately, but in batch.
                Logging.Log($"Applying {sideCarTags.Count} keywords from sidecar files to image {img.FileName}");
                _ = MetaDataService.Instance.UpdateTagsAsync(new[] { img }, sideCarTags, null);
            }
        }
Пример #12
0
        /**
         * XPath composition utilities using the <code>XmpPathFactory</code>.
         * @throws XmpException Forwards exceptions
         */
        private static void CoverPathCreation()
        {
            writeMajorLabel("XPath composition utilities");

            var meta = XmpMetaFactory.Create();

            meta.AppendArrayItem(TestData.NS1, "ArrayProp", new PropertyOptions {
                IsArray = true
            }, "Item 1", null);

            string path = XmpPathFactory.ComposeArrayItemPath("ArrayProp", 2);

            log.WriteLine("composeArrayItemPath ArrayProp[2] =   " + path);
            meta.SetProperty(TestData.NS1, path, "new ns1:ArrayProp[2] value");

            path  = "StructProperty";
            path += XmpPathFactory.ComposeStructFieldPath(TestData.NS2, "Field3");
            log.WriteLine("composeStructFieldPath StructProperty/ns2:Field3 =   " + path);
            meta.SetProperty(TestData.NS1, path, "new ns1:StructProp/ns2:Field3 value");

            path  = "QualProp";
            path += XmpPathFactory.ComposeQualifierPath(TestData.NS2, "Qual");
            log.WriteLine("composeStructFieldPath QualProp/?ns2:Qual =   " + path);
            meta.SetProperty(TestData.NS1, path, "new ns1:QualProp/?ns2:Qual value");

            meta.SetLocalizedText(TestData.NS1, "AltTextProp", null, "en-US", "initival value");
            path  = "AltTextProp";
            path += XmpPathFactory.ComposeQualifierPath(XmpConstants.NsXml, "lang");
            log.WriteLine("composeQualifierPath ns1:AltTextProp/?xml:lang =   " + path);
            meta.SetProperty(TestData.NS1, path, "new ns1:AltTextProp/?xml:lang value");

            printXmpMeta(meta, "Modified simple RDF");
        }
        public XmpDirectory Extract([NotNull] byte[] xmpBytes, int offset, int length)
        {
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(offset), "Must be zero or greater.");
            }
            if (length < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(length), "Must be zero or greater.");
            }
            if (xmpBytes.Length < offset + length)
            {
                throw new ArgumentException("Extends beyond length of byte array.", nameof(length));
            }

            // Trim any trailing null bytes
            // https://github.com/drewnoakes/metadata-extractor-dotnet/issues/154
            while (xmpBytes[offset + length - 1] == 0)
            {
                length--;
            }

            var directory = new XmpDirectory();

            try
            {
                var xmpMeta = XmpMetaFactory.ParseFromBuffer(xmpBytes, offset, length);
                directory.SetXmpMeta(xmpMeta);
            }
            catch (XmpException e)
            {
                directory.AddError("Error processing XMP data: " + e.Message);
            }
            return(directory);
        }
Пример #14
0
        /**
         * Literal value set/get methods
         * @throws XmpException
         */
        private static void CoverLiteralProperties()
        {
            writeMajorLabel("Test SetProperty... and getProperty... methods " +
                            "(set/get with literal values)");

            var meta      = XmpMetaFactory.ParseFromString(TestData.DATETIME_RDF);
            var dateValue = XmpDateTimeFactory.Create(2000, 1, 2, 3, 4, 5, 0);

            meta.SetPropertyBoolean(TestData.NS1, "Bool0", false);
            meta.SetPropertyBoolean(TestData.NS1, "Bool1", true);
            meta.SetPropertyInteger(TestData.NS1, "Int", 42);
            meta.SetPropertyDouble(TestData.NS1, "Double", 4.2);

            meta.SetPropertyDate(TestData.NS1, "Date10", dateValue);

/*
 *          TODO reinstate this code
 *
 *          int offset = (/* hour #1# 06 * 3600 * 1000 + /* minute #1# 07 * 60 * 1000) * /* sign #1# 1;
 *          dateValue.SetTimeZone(new SimpleTimeZone(offset, "test"));
 *          meta.SetPropertyDate (NS1, "Date11", dateValue);
 *          offset *= -1;
 *          dateValue.SetTimeZone(new SimpleTimeZone(offset, "test"));
 *          meta.SetPropertyDate (NS1, "Date12", dateValue);
 *          dateValue.SetNanosecond(9);
 *          meta.SetPropertyDate (NS1, "Date13", dateValue);
 */

            printXmpMeta(meta, "A few basic binary Set... calls");
            log.WriteLine();

            bool b = meta.GetPropertyBoolean(TestData.NS1, "Bool0");

            log.WriteLine("getPropertyBoolean ns1:Bool0 =   " + b);

            b = meta.GetPropertyBoolean(TestData.NS1, "Bool1");
            log.WriteLine("getPropertyBoolean ns1:Bool1 =   " + b);

            int integer = meta.GetPropertyInteger(TestData.NS1, "Int");

            log.WriteLine("getPropertyBoolean ns1:Int =   " + integer);

            double d = meta.GetPropertyDouble(TestData.NS1, "Double");

            log.WriteLine("getPropertyBoolean ns1:Int =   " + d);
            log.WriteLine();

            for (int i = 1; i <= 13; i++)
            {
                var dateName = "Date" + i;
                var dt       = meta.GetPropertyDate(TestData.NS1, dateName);
                log.WriteLine("getPropertyDate (" + i + ") =   " + dt);
                meta.SetPropertyDate(TestData.NS2, dateName, dateValue);
            }

            printXmpMeta(meta, "Get and re-set the dates in NS2");
        }
Пример #15
0
        public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding encoding)
        {
            var xmp = XmpMetaFactory.SerializeToString(context.Object as IXmpMeta, new SerializeOptions());

            using (var writer = context.WriterFactory(context.HttpContext.Response.Body, encoding))
            {
                return(writer.WriteAsync(xmp));
            }
        }
Пример #16
0
        private static IReadOnlyList <XmpDirectory> ReadJpegSegments(IEnumerable <JpegSegment> segments)
        {
            // This is a modified version of XmpReader.ReadJpegSegments
            // The original version specifically tests the buffer against the classic XMP preamble and discards everything else.
            // Here we also test against the extended XMP preamble and regroup all the extended segments into a single buffer.
            // Note that we do not import any of the usual tags as in ProcessXmpTags(). Users of the class have to go
            // through XmpMeta methods.

            var directories = new List <XmpDirectory>();

            byte[] extendedData = null;

            int maxPreambleLength = Math.Max(XmpJpegPreamble.Length, XmpJpegExtendedPreamble.Length);

            try
            {
                foreach (var segment in segments)
                {
                    string extractedPreamble = Encoding.UTF8.GetString(segment.Bytes, 0, maxPreambleLength);

                    if (extractedPreamble.StartsWith(XmpJpegPreamble))
                    {
                        ParseNormalXmpSegment(directories, segment.Bytes);
                    }
                    else if (extractedPreamble.StartsWith(XmpJpegExtendedPreamble))
                    {
                        ParseExtendedXmpSegment(ref extendedData, segment.Bytes);
                    }
                }
            }
            catch (JpegProcessingException)
            {
                return(directories);
            }

            if (extendedData == null)
            {
                return(directories);
            }

            // We have collected extended XMP data, let's parse the reconstructed buffer.
            XmpDirectory directory = new XmpDirectory();

            try
            {
                var xmpMeta = XmpMetaFactory.ParseFromBuffer(extendedData);
                directory.SetXmpMeta(xmpMeta);
            }
            catch (XmpException e)
            {
                directory.AddError("Error processing XMP data: " + e.Message);
            }

            directories.Add(directory);
            return(directories);
        }
Пример #17
0
        private void WriteXmpMetaData(string imageFilePath, MasterImage masterImage, bool alwaysWriteMetadata, bool preview)
        {
            bool writeMetadata = false;

            IXmpMeta xmp = XmpMetaFactory.Create();

            if ((!String.IsNullOrEmpty(masterImage.Caption) && !IsEquivalent(masterImage.Caption, imageFilePath)) || alwaysWriteMetadata)
            {
                xmp.AppendArrayItem(XmpConstants.NsDC, "dc:title", new PropertyOptions {
                    IsArrayAlternate = true
                }, masterImage.Caption, null);
                writeMetadata = true;
            }

            if (!String.IsNullOrEmpty(masterImage.Comment))
            {
                xmp.AppendArrayItem(XmpConstants.NsDC, "dc:description", new PropertyOptions {
                    IsArrayAlternate = true
                }, masterImage.Comment, null);
                writeMetadata = true;
            }

            if (masterImage.Rating != null && (int)masterImage.Rating > 0)
            {
                xmp.SetProperty(XmpConstants.NsXmp, "xmp:Rating", ((int)masterImage.Rating).ToString());
                writeMetadata = true;
            }

            // TODO: Handle faces.

            if (writeMetadata)
            {
                string metaFilePath = Path.ChangeExtension(imageFilePath, ".xmp");

                if (File.Exists(metaFilePath))
                {
                    Console.Error.WriteLine("ERROR: XMP meta file already exists, skipping '" + metaFilePath + "'.");
                }
                else if (!preview)
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(metaFilePath));

                    using (var stream = File.OpenWrite(metaFilePath))
                    {
                        XmpMetaFactory.Serialize(xmp, stream, new SerializeOptions {
                            OmitPacketWrapper = true
                        });
                    }

                    numMetadataFilesCreated++;
                }
            }
        }
Пример #18
0
        private void GenerateEAttachmentDocument(PdfAWriter writer, XmpWriter xmpWriter, EAttactment attachment)
        {
            // Use default intent if output intent of this instance was not set
            if (attachment.outputIntents == null)
            {
                //byte[] iccProfile = File.ReadAllBytes("/Resources/sRGB Color Space Profile.icm");
                byte[]      iccProfile = Properties.Resources.sRGB_Color_Space_Profile;
                ICC_Profile icc        = ICC_Profile.GetInstance(iccProfile);
                writer.SetOutputIntents("sRGB IEC61966-2.1", "", "http://www.color.org", "sRGB IEC61966-2.1", icc);
            }
            else
            {
                OutputIntents outputIntents       = attachment.outputIntents;
                byte[]        iccProfileByteArray = File.ReadAllBytes(outputIntents.colorProfilePath);
                ICC_Profile   icc = ICC_Profile.GetInstance(iccProfileByteArray);
                writer.SetOutputIntents(outputIntents.outputConditionIdentifier, outputIntents.outputCondition, outputIntents.registryName, outputIntents.info, icc);
            }

            //============= Create Exchange ECertificate =================
            // 1 add ContentInformation.xml to document
            PdfArray attachmentArray = new PdfArray();

            writer.ExtraCatalog.Put(new PdfName("AF"), attachmentArray);
            PdfFileSpecification contentSpec = this.EmbeddedAttachment(attachment.contentInformationXMLPath, attachment.attachmentName,
                                                                       attachment.attachmentMIME, new PdfName(attachment.attachmentType), writer, attachment.attachmentDescription);

            attachmentArray.Add(contentSpec.Reference);

            foreach (var item in attachment.fileAttachments)
            {
                contentSpec = this.EmbeddedAttachment(item.attachmentPath, item.attachmentName,
                                                      item.attachmentMIME, new PdfName(item.attachmentType), writer, item.attachmentDescription);
                attachmentArray.Add(contentSpec.Reference);
            }

            // 2 add Electronic Document XMP Metadata
            ElectronicDocumentSchema ed = ElectronicDocumentSchema.generateED(attachment.attachmentName, attachment.documentVersion, attachment.documentID, attachment.documentOID);

            xmpWriter.AddRdfDescription(ed);

            string pdfaSchema = Properties.Resources.EDocument_PDFAExtensionSchema;

            // convert string to stream
            byte[] byteArray = Encoding.UTF8.GetBytes(pdfaSchema);


            //byte[] byteArray = Encoding.ASCII.GetBytes(contents);
            MemoryStream stream          = new MemoryStream(byteArray);
            IXmpMeta     edPDFAextension = XmpMetaFactory.Parse(stream);
            IXmpMeta     originalXMP     = xmpWriter.XmpMeta;

            XmpUtils.AppendProperties(edPDFAextension, originalXMP, true, true);
        }
Пример #19
0
        /**
         * Flushes and closes the XmpWriter.
         * @throws IOException
         */

        virtual public void Close()
        {
            if (outputStream == null)
            {
                return;
            }
            try {
                XmpMetaFactory.Serialize(xmpMeta, outputStream, serializeOptions);
                outputStream = null;
            }
            catch (XmpException xmpExc) {
                throw new IOException(xmpExc.Message);
            }
        }
        /// <summary>
        /// Performs the XMP data extraction.
        /// <para />
        /// The extraction is done with Adobe's XMPCore library.
        /// </summary>
        public XmpDirectory Extract([NotNull] byte[] xmpBytes)
        {
            var directory = new XmpDirectory();

            try
            {
                var xmpMeta = XmpMetaFactory.ParseFromBuffer(xmpBytes);
                ProcessXmpTags(directory, xmpMeta);
            }
            catch (XmpException e)
            {
                directory.AddError("Error processing XMP data: " + e.Message);
            }
            return(directory);
        }
Пример #21
0
        public XmpDirectory Extract([NotNull] byte[] xmpBytes, int offset, int length)
        {
            var directory = new XmpDirectory();

            try
            {
                var xmpMeta = XmpMetaFactory.ParseFromBuffer(xmpBytes, offset, length);
                directory.SetXmpMeta(xmpMeta);
            }
            catch (XmpException e)
            {
                directory.AddError("Error processing XMP data: " + e.Message);
            }
            return(directory);
        }
Пример #22
0
        internal static IXmpMeta Get(ImageDetails details)
        {
            var xmp = XmpMetaFactory.Create();

            var idNs     = "https://id.parliament.uk/";
            var schemaNs = $"{idNs}schema/";

            XmpMetaFactory.SchemaRegistry.RegisterNamespace(idNs, "id");
            XmpMetaFactory.SchemaRegistry.RegisterNamespace(schemaNs, "schema");

            xmp.SetProperty(XmpConstants.NsIptccore, "CiAdrCity", "London");
            xmp.SetProperty(XmpConstants.NsIptccore, "CiAdrCtry", "UK");
            xmp.SetProperty(XmpConstants.NsIptccore, "CiAdrRegion", "London");
            xmp.SetProperty(XmpConstants.NsIptccore, "CiEmailWork", "*****@*****.**");
            xmp.SetProperty(XmpConstants.NsIptccore, "CiTelWork", "+447740424810");
            xmp.SetProperty(XmpConstants.NsIptccore, "CiUrlWork", "http://www.mcandrewphoto.co.uk");

            xmp.SetProperty(XmpConstants.NsPhotoshop, "Source", "Chris McAndrew / UK Parliament");
            xmp.SetProperty(XmpConstants.NsPhotoshop, "Credit", "Chris McAndrew / UK Parliament (Attribution 3.0 Unported (CC BY 3.0))");
            xmp.SetPropertyDate(XmpConstants.NsPhotoshop, "DateCreated", XmpDateTimeFactory.Create(2017, 6, 17, 11, 30, 41, 0));

            xmp.SetProperty(XmpConstants.NsDC, "rights", "Attribution 3.0 Unported (CC BY 3.0)");
            xmp.SetProperty(XmpConstants.NsDC, "title", $"{details.GivenName} {details.FamilyName}");
            xmp.SetProperty(XmpConstants.NsDC, "description", $"{details.GivenName} {details.FamilyName} - UK Parliament official portraits 2017");
            xmp.SetProperty(XmpConstants.NsDC, "creator", "Chris McAndrew / UK Parliament");

            // <rdf:Description rdf:about="http://id.parliament.uk/IMAGE1" />
            xmp.SetObjectName($"{idNs}{details.Id}");

            // id:IMAGE1 a schema:Image
            xmp.SetProperty(XmpConstants.NsRdf, "type", $"{schemaNs}Image", new PropertyOptions {
                IsUri = true
            });

            // id:IMAGE1 schema:parlHasSubject id:PERSON1
            xmp.SetProperty(schemaNs, "imageHasSubject", details.MemberUri, new PropertyOptions {
                IsUri = true
            });

            // id:PERSON1 a schema:Person
            xmp.SetQualifier(schemaNs, "imageHasSubject", XmpConstants.NsRdf, "type", $"{schemaNs}Person", new PropertyOptions {
                IsUri = true
            });

            return(xmp);
        }
Пример #23
0
 virtual public void AddRdfDescription(XmpSchema s)
 {
     try {
         String str = "<rdf:RDF xmlns:rdf=\"" + XmpConst.NS_RDF + "\">" +
                      "<rdf:Description rdf:about=\"" + xmpMeta.ObjectName +
                      "\" " +
                      s.Xmlns +
                      ">" +
                      s.ToString() +
                      "</rdf:Description></rdf:RDF>\n";
         IXmpMeta extMeta = XmpMetaFactory.ParseFromString(str);
         XmpUtils.AppendProperties(extMeta, xmpMeta, true, true);
     }
     catch (XmpException xmpExc) {
         throw new IOException(xmpExc.Message);
     }
 }
Пример #24
0
        private static void HandleFile(FileInfo file)
        {
            // Console.WriteLine("{0}", file.Name);


            IXmpMeta xmp;
            String   curFile = file.FullName.ToString();

            // using (var stream = File.OpenRead(file.DirectoryName + "/" + file.Name))
            using (var stream = File.OpenRead(curFile))
                xmp = XmpMetaFactory.Parse(stream);
            Boolean success = false;

            foreach (var property in xmp.Properties)
            {
                success = false;
                //Console.WriteLine($"Path={property.Path} Namespace={property.Namespace} Value={property.Value}");
                //  Console.WriteLine($"Path={property.Path} Value={property.Value}");

                //  if (property.Path == "crs:Look/crs:Name"|| property.Path == "crs:Name[1]")
                if (property.Path == "crs:Name[1]")
                {
                    string newfilename = property.Value.Trim().Replace('/', '-') + ".xmp";
                    if (string.Compare(newfilename, file.Name.ToString(), CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) == 0)
                    //  if (newfilename != file.Name)
                    {
                        break;
                    }
                    else
                    {
                        file.CopyTo(file.DirectoryName + "/" + file.Name + "_old", true);

                        file.CopyTo(file.DirectoryName + "/" + newfilename, true);
                        Console.WriteLine(property.Value);
                        success = true;

                        break;
                    }
                }
            }
            if (success == true)
            {
                file.Delete();
            }
        }
Пример #25
0
 public void AddRdfDescription(String xmlns, String content)
 {
     try {
         String str = "<rdf:RDF xmlns:rdf=\"" + XmpConst.NS_RDF + "\">" +
                      "<rdf:Description rdf:about=\"" + xmpMeta.ObjectName +
                      "\" " +
                      xmlns +
                      ">" +
                      content +
                      "</rdf:Description></rdf:RDF>\n";
         byte[]   bytes   = Encoding.Convert(Encoding.UTF8, Encoding.ASCII, Encoding.UTF8.GetBytes(str));
         IXmpMeta extMeta = XmpMetaFactory.ParseFromString(str);
         XmpUtils.AppendProperties(extMeta, xmpMeta, true, true);
     }
     catch (XmpException xmpExc) {
         throw new IOException(xmpExc.Message);
     }
 }
        public XmpDirectory Extract([NotNull] byte[] xmpBytes, int offset, int length)
        {
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(offset), "Must be zero or greater.");
            }
            if (length < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(length), "Must be zero or greater.");
            }
            if (xmpBytes.Length < offset + length)
            {
                throw new ArgumentException("Extends beyond length of byte array.", nameof(length));
            }

            // Trim any trailing null bytes
            // https://github.com/drewnoakes/metadata-extractor-dotnet/issues/154
            while (xmpBytes[offset + length - 1] == 0)
            {
                length--;
            }

            var directory = new XmpDirectory();

            try
            {
                // Limit photoshop:DocumentAncestors node as it can reach over 100000 items and make parsing extremely slow.
                // This is not a typical value but it may happen https://forums.adobe.com/thread/2081839
                var parseOptions = new ParseOptions();
                parseOptions.SetXMPNodesToLimit(new Dictionary <string, int>()
                {
                    { "photoshop:DocumentAncestors", 1000 }
                });

                var xmpMeta = XmpMetaFactory.ParseFromBuffer(xmpBytes, offset, length, parseOptions);
                directory.SetXmpMeta(xmpMeta);
            }
            catch (XmpException e)
            {
                directory.AddError("Error processing XMP data: " + e.Message);
            }
            return(directory);
        }
Пример #27
0
        private static void ParseNormalXmpSegment(List <XmpDirectory> directories, byte[] segmentBytes)
        {
            byte[] xmpBytes = new byte[segmentBytes.Length - XmpJpegPreamble.Length];
            Array.Copy(segmentBytes, XmpJpegPreamble.Length, xmpBytes, 0, xmpBytes.Length);

            XmpDirectory directory = new XmpDirectory();

            try
            {
                var xmpMeta = XmpMetaFactory.ParseFromBuffer(xmpBytes);
                directory.SetXmpMeta(xmpMeta);
            }
            catch (XmpException e)
            {
                directory.AddError("Error processing XMP data: " + e.Message);
            }

            directories.Add(directory);
        }
Пример #28
0
    /// <summary>
    /// Given a sidecar object, parses the files (ON1 or XMP) and pulls out
    /// the list of keywords in the sidecar file.
    /// </summary>
    /// <param name="sidecar"></param>
    /// <returns></returns>
    public static IList <string> GetKeywords(this ImageSideCar sidecar)
    {
        var sideCarTags = new List <string>();

        // If there's an On1 sidecar, read it
        try
        {
            if (sidecar.Type == SidecarUtils.SidecarType.ON1)
            {
                var on1MetaData = On1Sidecar.LoadMetadata(sidecar.Filename);

                if (on1MetaData != null && on1MetaData.Keywords != null && on1MetaData.Keywords.Any())
                {
                    sideCarTags = on1MetaData.Keywords
                                  .Select(x => x.Trim())
                                  .ToList();
                }
            }

            // If there's an XMP sidecar
            if (sidecar.Type == SidecarUtils.SidecarType.XMP)
            {
                using var stream = File.OpenRead(sidecar.Filename.FullName);
                IXmpMeta xmp = XmpMetaFactory.Parse(stream);

                var xmpKeywords = xmp.Properties.FirstOrDefault(x => x.Path == "pdf:Keywords");

                if (xmpKeywords != null)
                {
                    sideCarTags = xmpKeywords.Value.Split(",")
                                  .Select(x => x.Trim())
                                  .ToList();
                }
            }
        }
        catch (Exception ex)
        {
            Logging.LogError($"Exception processing {sidecar.Type} sidecar: {sidecar.Filename.FullName}: {ex.Message}");
        }

        return(sideCarTags);
    }
Пример #29
0
        public void XXE_DoctypeEnabled()
        {
            string testdata = @"<!DOCTYPE doc [<!ENTITY win SYSTEM ""c:\windows\win.ini"">]><doc></doc>";

            var options = new Options.ParseOptions();

            // enable doctype
            options.DisallowDoctype = false;
            Exception e = null;

            try
            {
                XmpMetaFactory.ParseFromString(testdata, options);
            }
            catch (Exception ex)
            {
                e = ex;
            }
            Assert.Null(e);
        }
Пример #30
0
        /**
         * Creates an XmpWriter.
         * @param os
         * @param utfEncoding
         * @param extraSpace
         * @throws IOException
         */

        public XmpWriter(Stream os, String utfEncoding, int extraSpace)
        {
            outputStream     = os;
            serializeOptions = new SerializeOptions();
            if (UTF16BE.Equals(utfEncoding) || UTF16.Equals(utfEncoding))
            {
                serializeOptions.EncodeUtf16Be = true;
            }
            else if (UTF16LE.Equals(utfEncoding))
            {
                serializeOptions.EncodeUtf16Le = true;
            }
            serializeOptions.Padding = extraSpace;
            xmpMeta            = XmpMetaFactory.Create();
            xmpMeta.ObjectName = XmpConst.TAG_XMPMETA;
            xmpMeta.ObjectName = "";
            try {
                xmpMeta.SetProperty(XmpConst.NS_DC, DublinCoreProperties.FORMAT, "application/pdf");
                xmpMeta.SetProperty(XmpConst.NS_PDF, PdfProperties.PRODUCER, Version.GetInstance().GetVersion);
            }
            catch (XmpException) {}
        }