Beispiel #1
0
        public void WriteSegment(JpegSegment segment)
        {
            if (segment == null)
            {
                throw new ArgumentNullException(nameof(segment));
            }
            if (segment.Bytes.Length + 2 > 0xFFFF)
            {
                throw new ArgumentOutOfRangeException(nameof(segment));
            }

            _writer.Write((byte)0xFF); // segment start
            _writer.Write((byte)segment.Type);

            if (HasData(segment.Type))
            {
                // write size as big endian ushort
                var size = segment.Bytes.Length + 2; // + 2 for the size bytes
                _writer.Write((byte)(size >> 8));
                _writer.Write((byte)(size & 0xFF));

                // write data
                _writer.Write(segment.Bytes, 0, segment.Bytes.Length);
            }
        }
Beispiel #2
0
        public void ReadJpegSegmentWithNoExifData()
        {
            var badExifSegment = new JpegSegment(JpegSegmentType.App1, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, offset: 0);
            var directories    = new ExifReader().ReadJpegSegments(new[] { badExifSegment });

            Assert.Equal(0, directories.Count);
        }
Beispiel #3
0
        public void Parse_ThumbnailData()
        {
            var dir = new ExifThumbnailDirectory();

            dir.Set(ExifThumbnailDirectory.TagThumbnailOffset, 0);
            dir.Set(ExifThumbnailDirectory.TagThumbnailLength, 2);

            var segment = new JpegSegment(JpegSegmentType.App1, new byte[]
            {
                (byte)'E',
                (byte)'x',
                (byte)'i',
                (byte)'f',
                (byte)'\0',
                (byte)'\0',
                0x12, 0x23, 0x34
            }, 0);

            var metadata = new Mock <IExifMetadata>();

            metadata.Setup(mock => mock.Segment).Returns(segment);
            metadata.Setup(mock => mock.GetDirectoryOfType <ExifDirectoryBase>()).Returns(dir);

            var parser    = new ThumbnaiExifAttributeParser <ExifDirectoryBase>("thumbnail");
            var thumbnail = parser.Parse(metadata.Object).Value as ImageValue;

            CollectionAssert.AreEqual(new byte[] { 0x12, 0x23 }, thumbnail.Value);
        }
        public void ReadJpegSegments_InvalidData()
        {
            var app2      = new JpegSegment(JpegSegmentType.App2, File.ReadAllBytes("Data/iccDataInvalid1.jpg.app2"), offset: 0);
            var directory = new IccReader().ReadJpegSegments(new[] { app2 });

            Assert.NotNull(directory);
            Assert.True(directory.Single().HasError);
        }
Beispiel #5
0
        public void MatchSegment_ValidHeaderAndType()
        {
            var segment = new JpegSegment(JpegSegmentType.App1, new byte[]
            {
                (byte)'T', (byte)'e', (byte)'s', (byte)'t', 0x00, 0x12, 0x34
            }, 0);

            Assert.IsTrue(JpegSegmentUtils.MatchSegment(segment, JpegSegmentType.App1, "Test\0"));
        }
        public void Extract_ProfileDateTime()
        {
            var app2 = new JpegSegment(JpegSegmentType.App2, File.ReadAllBytes("Data/withExifAndIptc.jpg.app2"), offset: 0);

            var directory = new IccReader()
                            .ReadJpegSegments(new[] { app2 })
                            .OfType <IccDirectory>()
                            .Single();

            Assert.NotNull(directory);
//            Assert.Equal("1998:02:09 06:49:00", directory.GetString(IccDirectory.TagProfileDateTime));
            Assert.Equal(new DateTime(1998, 2, 9, 6, 49, 0), directory.GetDateTime(IccDirectory.TagProfileDateTime));
        }
        public void WriteSegment_SegmentWithoutData()
        {
            var output = new MemoryStream();
            var writer = new JpegSegmentWriter(new BinaryWriter(output));

            var segment = new JpegSegment(JpegSegmentType.Soi, new byte[0], 0);

            writer.WriteSegment(segment);

            var result = output.ToArray();

            CollectionAssert.AreEqual(
                new byte[] { 0xFF, 0xD8 },
                result);
        }
        public void WriteSegment_SegmentWithData()
        {
            var output = new MemoryStream();
            var writer = new JpegSegmentWriter(new BinaryWriter(output));

            var segment = new JpegSegment(JpegSegmentType.App1, new byte[] { 0x12, 0x34, 0x56 }, 0);

            writer.WriteSegment(segment);

            var result = output.ToArray();

            CollectionAssert.AreEqual(
                new byte[] { 0xFF, 0xE1, 0x00, 0x05, 0x12, 0x34, 0x56 },
                result);
        }
Beispiel #9
0
        /// <summary>
        /// Check segment type and header.
        /// </summary>
        /// <param name="segment">JPEG segment</param>
        /// <param name="type">Expected type</param>
        /// <param name="header">Expected header</param>
        /// <returns>true iff the segment has given type and header</returns>
        public static bool MatchSegment(JpegSegment segment, JpegSegmentType type, string header)
        {
            if (segment.Type != type || segment.Bytes.Length < header.Length)
            {
                return(false);
            }

            for (int i = 0; i < header.Length; ++i)
            {
                if ((char)segment.Bytes[i] != header[i])
                {
                    return(false);
                }
            }

            return(true);
        }
 private static bool IsXmpSegment(JpegSegment segment) => segment.Bytes.StartsWith(JpegSegmentPreambleBytes);
 private static bool IsExtendedXmpSegment(JpegSegment segment) => segment.Bytes.StartsWith(JpegSegmentPreambleExtensionBytes);
Beispiel #12
0
        public override FileMetadata AnalyzeFile()
        {
            try
            {
                this.foundMetadata = new FileMetadata();
                IReadOnlyList <MetadataExtractor.Directory> directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(this.fileStream);

                foreach (MetadataExtractor.Directory currentDir in directories.Where(p => !IgnoredExifDirectories.Contains(p.Name)))
                {
                    if (currentDir is MetadataExtractor.Formats.Exif.ExifThumbnailDirectory)
                    {
                        try
                        {
                            uint offset = (uint)currentDir.GetObject(MetadataExtractor.Formats.Exif.ExifThumbnailDirectory.TagThumbnailOffset) + (uint)MetadataExtractor.Formats.Exif.ExifReader.JpegSegmentPreamble.Length;
                            uint length = (uint)currentDir.GetObject(MetadataExtractor.Formats.Exif.ExifThumbnailDirectory.TagThumbnailLength);

                            long currentPosition = this.fileStream.Position;
                            this.fileStream.Seek(0, SeekOrigin.Begin);
                            JpegSegment app1Segment = JpegSegmentReader.ReadSegments(new MetadataExtractor.IO.SequentialStreamReader(this.fileStream), new[] { JpegSegmentType.App1 }).FirstOrDefault();
                            if (app1Segment != null)
                            {
                                byte[] thumb = new byte[length];
                                Array.Copy(app1Segment.Bytes, offset, thumb, 0, length);
                                this.foundMetadata.Thumbnail = thumb;
                            }
                            this.fileStream.Seek(currentPosition, SeekOrigin.Begin);
                        }
                        catch (Exception)
                        {
                        }
                    }
                    else if (currentDir is MetadataExtractor.Formats.Exif.GpsDirectory gps)
                    {
                        if (this.foundMetadata.GPS == null)
                        {
                            MetadataExtractor.GeoLocation gpsLocation = gps.GetGeoLocation();
                            if (gpsLocation != null)
                            {
                                this.foundMetadata.GPS = new GeoLocation(gpsLocation.ToDmsString(), gpsLocation.Longitude, gpsLocation.Latitude);
                                if (gps.ContainsTag(MetadataExtractor.Formats.Exif.GpsDirectory.TagAltitude))
                                {
                                    this.foundMetadata.GPS.Altitude = $"{gps.GetDescription(MetadataExtractor.Formats.Exif.GpsDirectory.TagAltitude)} ({gps.GetDescription(MetadataExtractor.Formats.Exif.GpsDirectory.TagAltitudeRef)})";;
                                }
                            }
                        }
                    }
                    else
                    {
                        Dictionary <string, string> dicTags = new Dictionary <string, string>();
                        foreach (MetadataExtractor.Tag tag in currentDir.Tags)
                        {
                            string lcDescription = tag.Description?.Trim();
                            string lcName        = tag.Name?.Trim();

                            if (!String.IsNullOrWhiteSpace(lcName) && !String.IsNullOrWhiteSpace(lcDescription) &&
                                !lcName.StartsWith("unknown", StringComparison.OrdinalIgnoreCase) && !lcDescription.ToLower().StartsWith("unknown", StringComparison.OrdinalIgnoreCase))
                            {
                                lcName        = Functions.RemoveAccentsWithNormalization(lcName);
                                lcDescription = Functions.RemoveAccentsWithNormalization(lcDescription);

                                switch (tag.Type)
                                {
                                case MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagWinAuthor:
                                case MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist:
                                case MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagCameraOwnerName:
                                    this.foundMetadata.Add(new User(lcDescription, false, "EXIF"));
                                    break;

                                case MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagSoftware:
                                    string strSoftware = Analysis.ApplicationAnalysis.GetApplicationsFromString(lcDescription);
                                    if (!String.IsNullOrEmpty(strSoftware))
                                    {
                                        this.foundMetadata.Add(new Application(strSoftware));
                                    }
                                    break;

                                case MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTime:
                                case MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeDigitized:
                                case MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal:
                                    if (DateTime.TryParseExact(lcDescription, "yyyy:MM:dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date) &&
                                        date > DateTime.MinValue && (!foundMetadata.Dates.CreationDate.HasValue || this.foundMetadata.Dates.CreationDate > date))
                                    {
                                        this.foundMetadata.Dates.CreationDate = date;
                                    }
                                    break;

                                case MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagModel:
                                    this.foundMetadata.Model = lcDescription;
                                    break;

                                case MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagHostComputer:
                                    this.foundMetadata.OperatingSystem = lcDescription;
                                    break;

                                default:
                                    break;
                                }

                                if (!dicTags.ContainsKey(lcName))
                                {
                                    dicTags.Add(lcName, lcDescription);
                                }
                            }
                        }

                        if (dicTags.Count > 0)
                        {
                            string makerKey = currentDir.Name;
                            int    i        = 1;
                            while (foundMetadata.Makernotes.ContainsKey(makerKey))
                            {
                                makerKey = $"{currentDir.Name} ({i})";
                                i++;
                            }

                            foundMetadata.Makernotes.Add(makerKey, dicTags);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine($"Error analizing EXIF metadata ({e.ToString()})");
            }

            return(this.foundMetadata);
        }
 private static string GetExtendedDataGuid(JpegSegment segment) => Encoding.UTF8.GetString(segment.Bytes, JpegSegmentPreambleExtensionBytes.Length, 32);
Beispiel #14
0
 private bool IsExifSegment(JpegSegment segment)
 {
     return(segment.Type == JpegSegmentType.App1 &&
            Encoding.UTF8.GetString(segment.Bytes, 0, ExifHeader.Length) == ExifHeader);
 }
        public JpegReaderTest()
        {
            var sof0 = new JpegSegment(JpegSegmentType.Sof0, File.ReadAllBytes("Data/simple.jpg.sof0"), offset: 0);

            _directory = new JpegReader().Extract(sof0);
        }
Beispiel #16
0
        public static IList <Directory> ProcessSegmentBytes(string filePath, JpegSegmentType type)
        {
            var segment = new JpegSegment(type, TestDataUtil.GetBytes(filePath), 0);

            return(new ExifReader().ReadJpegSegments(new[] { segment }).ToList());
        }
Beispiel #17
0
        private static bool IsAttributeSegment(JpegSegment segment)
        {
            const string header = AttributeReader.JpegSegmentHeader;

            return(JpegSegmentUtils.MatchSegment(segment, JpegSegmentType.App1, header));
        }
Beispiel #18
0
 public ExifMetadata(JpegSegment segment, IReadOnlyList <Directory> directories)
 {
     Segment      = segment;
     _directories = directories;
 }
Beispiel #19
0
        public void MatchSegment_InvalidType()
        {
            var segment = new JpegSegment(JpegSegmentType.App0, new byte[0], 0);

            Assert.IsFalse(JpegSegmentUtils.MatchSegment(segment, JpegSegmentType.App1, "Test\0"));
        }
Beispiel #20
0
        public void MatchSegment_ShortHeader()
        {
            var segment = new JpegSegment(JpegSegmentType.App1, new byte[0], 0);

            Assert.IsFalse(JpegSegmentUtils.MatchSegment(segment, JpegSegmentType.App1, "Test\0"));
        }
Beispiel #21
0
        public static IEnumerable <JpegSegment> ReadSegments(SequentialStreamReWriter reader, Stream writer
                                                             , ICollection <IJpegSementMetadataReWriter> segmentProcessors)
        {
            if (segmentProcessors == null || segmentProcessors.Count() <= 0)
            {
                throw new ArgumentException(nameof(segmentProcessors));
            }
            // Build the union of segment types desired by all readers
            var segmentTypes = new HashSet <JpegSegmentType>(segmentProcessors.SelectMany(reader => reader.SegmentTypes));


            if (!reader.IsMotorolaByteOrder)
            {
                throw new JpegProcessingException("Must be big-endian/Motorola byte order.");
            }

            // first two bytes should be JPEG magic number
            var magicTupleData = reader.GetBytes(2);
            var magicNumber    = reader.GetUInt16(magicTupleData);

            Write(writer, magicTupleData);

            if (magicNumber != 0xFFD8)
            {
                throw new JpegProcessingException($"JPEG data is expected to begin with 0xFFD8 (ÿØ) not 0x{magicNumber:X4}");
            }

            do
            {
                // Find the segment marker. Markers are zero or more 0xFF bytes, followed
                // by a 0xFF and then a byte not equal to 0x00 or 0xFF.
                var segmentIdentifier = reader.GetByte();
                Write(writer, segmentIdentifier);
                var segmentTypeByte = reader.GetByte();
                Write(writer, segmentTypeByte);

                // Read until we have a 0xFF byte followed by a byte that is not 0xFF or 0x00
                while (segmentIdentifier != 0xFF || segmentTypeByte == 0xFF || segmentTypeByte == 0)
                {
                    segmentIdentifier = segmentTypeByte;
                    segmentTypeByte   = reader.GetByte();
                    Write(writer, segmentTypeByte);
                }

                var segmentType = (JpegSegmentType)segmentTypeByte;



                if (segmentType == JpegSegmentType.Eoi)
                {
                    // the 'End-Of-Image' segment
                    yield break;
                }

                // next 2-bytes are <segment-size>: [high-byte] [low-byte]
                var segmentLenghtDataData = reader.GetBytes(2);
                var segmentLenghtData     = reader.GetUInt16(segmentLenghtDataData);
                Write(writer, segmentLenghtDataData);

                var segmentLength = (int)segmentLenghtData;
                // segment length includes size bytes, so subtract two
                segmentLength -= 2;

                if (segmentLength < 0)
                {
                    throw new JpegProcessingException("JPEG segment size would be less than zero");
                }

                if (segmentType == JpegSegmentType.Sos)
                {
                    // The 'Start-Of-Scan' segment's length doesn't include the image data, instead would
                    // have to search for the two bytes: 0xFF 0xD9 (EOI).
                    // It comes last so simply return at this point
                    reader.CopyRemainingBytes(writer);

                    yield break;
                }

                // Check whether we are interested in this segment
                if (segmentTypes.Contains(segmentType))
                {
                    var segmentOffset = reader.Position;
                    var segmentBytes  = reader.GetBytes(segmentLength);
                    //Write(writer, segmentBytes); // components are responsable for writing themselfs
                    Debug.Assert(segmentLength == segmentBytes.Length);

                    var orignialSegmentContent = new JpegSegment(segmentType, segmentBytes, segmentOffset);
                    var segmentProcessor       = segmentProcessors.FirstOrDefault(x => x.SegmentTypes.Contains(segmentType));

                    // should not happen
                    if (segmentProcessor == null)
                    {
                        throw new InvalidOperationException("Segment processor for {segmentType} not found");
                    }

                    var result = segmentProcessor.ReadJpegSegments(new JpegSegment[] { orignialSegmentContent }, writer);

                    yield return(orignialSegmentContent); // [sno] todo - remove return here
                }
                else
                {
                    // Any other segment
                    var segmentBytes = reader.GetBytes(segmentLength);
                    Write(writer, segmentBytes);
                }
            }while (true);
        }
        public static IList <Directory> ProcessSegmentBytes([NotNull] string filePath, JpegSegmentType type)
        {
            var segment = new JpegSegment(type, File.ReadAllBytes(filePath), 0);

            return(new ExifReader().ReadJpegSegments(new[] { segment }).ToList());
        }