public void AutoOrient_WorksWithCorruptExifData <TPixel>(TestImageProvider <TPixel> provider, ExifDataType dataType, byte[] orientation) where TPixel : unmanaged, IPixel <TPixel> { var profile = new ExifProfile(); profile.SetValue(ExifTag.JPEGTables, orientation); byte[] bytes = profile.ToByteArray(); // Change the tag into ExifTag.Orientation bytes[16] = 18; bytes[17] = 1; // Change the data type bytes[18] = (byte)dataType; // Change the number of components bytes[20] = 1; var orientationCodeData = new byte[8]; Array.Copy(orientation, orientationCodeData, orientation.Length); ulong orientationCode = BitConverter.ToUInt64(orientationCodeData, 0); using (Image <TPixel> image = provider.GetImage()) using (Image <TPixel> reference = image.Clone()) { image.Metadata.ExifProfile = new ExifProfile(bytes); image.Mutate(x => x.AutoOrient()); image.DebugSave(provider, $"{dataType}-{orientationCode}", appendPixelTypeToFileName: false); ImageComparer.Exact.VerifySimilarity(image, reference); } }
/// <summary> /// Writes the EXIF profile. /// </summary> /// <param name="exifProfile">The exif profile.</param> /// <exception cref="ImageFormatException"> /// Thrown if the EXIF profile size exceeds the limit /// </exception> private void WriteExifProfile(ExifProfile exifProfile) { const int Max = 65533; byte[] data = exifProfile?.ToByteArray(); if (data == null || data.Length == 0) { return; } if (data.Length > Max) { throw new ImageFormatException($"Exif profile size exceeds limit. nameof{Max}"); } int length = data.Length + 2; this.buffer[0] = JpegConstants.Markers.XFF; this.buffer[1] = JpegConstants.Markers.APP1; // Application Marker this.buffer[2] = (byte)((length >> 8) & 0xFF); this.buffer[3] = (byte)(length & 0xFF); this.outputStream.Write(this.buffer, 0, 4); this.outputStream.Write(data, 0, data.Length); }
public void ConstructorImageMetaData() { ImageMetaData metaData = new ImageMetaData(); ExifProfile exifProfile = new ExifProfile(); ImageProperty imageProperty = new ImageProperty("name", "value"); metaData.ExifProfile = exifProfile; metaData.FrameDelay = 42; metaData.HorizontalResolution = 4; metaData.VerticalResolution = 2; metaData.Properties.Add(imageProperty); metaData.Quality = 24; metaData.RepeatCount = 1; metaData.DisposalMethod = DisposalMethod.RestoreToBackground; ImageMetaData clone = new ImageMetaData(metaData); Assert.Equal(exifProfile.ToByteArray(), clone.ExifProfile.ToByteArray()); Assert.Equal(42, clone.FrameDelay); Assert.Equal(4, clone.HorizontalResolution); Assert.Equal(2, clone.VerticalResolution); Assert.Equal(imageProperty, clone.Properties[0]); Assert.Equal(24, clone.Quality); Assert.Equal(1, clone.RepeatCount); Assert.Equal(DisposalMethod.RestoreToBackground, clone.DisposalMethod); }
public void ShouldReturnEmptyArrayWhenEmpty() { var profile = new ExifProfile(); var bytes = profile.ToByteArray(); Assert.Empty(bytes); }
public void ShouldReturnEmptyArrayWhenEmpty() { var profile = new ExifProfile(); var bytes = profile.ToByteArray(); Assert.AreEqual(0, bytes.Length); }
public void ShouldReturnOriginalDataWhenNotParsed() { using (IMagickImage image = new MagickImage(Files.FujiFilmFinePixS1ProJPG)) { ExifProfile profile = image.GetExifProfile(); var bytes = profile.ToByteArray(); Assert.AreEqual(4706, bytes.Length); } }
public void ShouldExcludeEmptyStrings() { var profile = new ExifProfile(); profile.SetValue(ExifTag.ImageDescription, string.Empty); var data = profile.ToByteArray(); var result = ExifReader.Read(data); Assert.Empty(result.Values); }
/// <summary> /// Writes the encoded image to the stream. /// </summary> /// <param name="stream">The stream to write to.</param> /// <param name="exifProfile">The exif profile.</param> /// <param name="width">The width of the image.</param> /// <param name="height">The height of the image.</param> /// <param name="hasAlpha">Flag indicating, if a alpha channel is present.</param> public void WriteEncodedImageToStream(Stream stream, ExifProfile exifProfile, uint width, uint height, bool hasAlpha) { bool isVp8X = false; byte[] exifBytes = null; uint riffSize = 0; if (exifProfile != null) { isVp8X = true; riffSize += ExtendedFileChunkSize; exifBytes = exifProfile.ToByteArray(); riffSize += this.ExifChunkSize(exifBytes); } this.Finish(); uint size = (uint)this.NumBytes(); size++; // One byte extra for the VP8L signature. // Write RIFF header. uint pad = size & 1; riffSize += WebpConstants.TagSize + WebpConstants.ChunkHeaderSize + size + pad; this.WriteRiffHeader(stream, riffSize); // Write VP8X, header if necessary. if (isVp8X) { this.WriteVp8XHeader(stream, exifProfile, width, height, hasAlpha); } // Write magic bytes indicating its a lossless webp. stream.Write(WebpConstants.Vp8LMagicBytes); // Write Vp8 Header. BinaryPrimitives.WriteUInt32LittleEndian(this.scratchBuffer, size); stream.Write(this.scratchBuffer.AsSpan(0, 4)); stream.WriteByte(WebpConstants.Vp8LHeaderMagicByte); // Write the encoded bytes of the image to the stream. this.WriteToStream(stream); if (pad == 1) { stream.WriteByte(0); } if (exifProfile != null) { this.WriteExifProfile(stream, exifBytes); } }
public void EmptyWriter() { var profile = new ExifProfile() { Parts = ExifParts.GpsTags }; profile.SetValue(ExifTag.Copyright, "Copyright text"); byte[] bytes = profile.ToByteArray(); Assert.NotNull(bytes); Assert.Empty(bytes); }
public void ShouldExcludeNullValues() { var profile = new ExifProfile(); profile.SetValue(ExifTag.ImageDescription, null); var data = profile.ToByteArray(); var reader = new ExifReader(); reader.Read(data); Assert.AreEqual(0, reader.Values.Count); }
public void ShouldExcludeNullValues() { var profile = new ExifProfile(); profile.SetValue(ExifTag.ImageDescription, null); var data = profile.ToByteArray(); var reader = new ExifReader(); reader.Read(data); EnumerableAssert.IsEmpty(reader.Values); }
public void ShouldReturnEmptyArrayWhenAllValuesAreInvalid() { var bytes = new byte[] { 69, 120, 105, 102, 0, 0, 73, 73, 42, 0, 8, 0, 0, 0, 1, 0, 42, 1, 4, 0, 1, 0, 0, 0, 42, 0, 0, 0, 26, 0, 0, 0, 0, 0 }; var profile = new ExifProfile(bytes); var unkownTag = new ExifTag <uint>((ExifTagValue)298); var value = profile.GetValue <uint>(unkownTag); Assert.AreEqual(42U, value.GetValue()); Assert.AreEqual("42", value.ToString()); bytes = profile.ToByteArray(); Assert.AreEqual(0, bytes.Length); }
public void TestArrayValueWithUnspecifiedSize() { // This images contains array in the exif profile that has zero components. Image <Rgba32> image = TestFile.Create(TestImages.Jpeg.Issues.InvalidCast520).CreateImage(); ExifProfile profile = image.MetaData.ExifProfile; Assert.NotNull(profile); // Force parsing of the profile. Assert.Equal(24, profile.Values.Count); byte[] bytes = profile.ToByteArray(); Assert.Equal(489, bytes.Length); }
public void ConstructorImageMetadata() { var metaData = new ImageMetadata(); var exifProfile = new ExifProfile(); metaData.ExifProfile = exifProfile; metaData.HorizontalResolution = 4; metaData.VerticalResolution = 2; ImageMetadata clone = metaData.DeepClone(); Assert.Equal(exifProfile.ToByteArray(), clone.ExifProfile.ToByteArray()); Assert.Equal(4, clone.HorizontalResolution); Assert.Equal(2, clone.VerticalResolution); }
/// <summary> /// Writes the EXIF profile. /// </summary> /// <param name="exifProfile">The exif profile.</param> private void WriteExifProfile(ExifProfile exifProfile) { if (exifProfile is null || exifProfile.Values.Count == 0) { return; } const int MaxBytesApp1 = 65533; // 64k - 2 padding bytes const int MaxBytesWithExifId = 65527; // Max - 6 bytes for EXIF header. byte[] data = exifProfile.ToByteArray(); if (data.Length == 0) { return; } // We can write up to a maximum of 64 data to the initial marker so calculate boundaries. int exifMarkerLength = ProfileResolver.ExifMarker.Length; int remaining = exifMarkerLength + data.Length; int bytesToWrite = remaining > MaxBytesApp1 ? MaxBytesApp1 : remaining; int app1Length = bytesToWrite + 2; // Write the app marker, EXIF marker, and data this.WriteApp1Header(app1Length); this.outputStream.Write(ProfileResolver.ExifMarker); this.outputStream.Write(data, 0, bytesToWrite - exifMarkerLength); remaining -= bytesToWrite; // If the exif data exceeds 64K, write it in multiple APP1 Markers for (int idx = MaxBytesWithExifId; idx < data.Length; idx += MaxBytesWithExifId) { bytesToWrite = remaining > MaxBytesWithExifId ? MaxBytesWithExifId : remaining; app1Length = bytesToWrite + 2 + exifMarkerLength; this.WriteApp1Header(app1Length); // Write Exif00 marker this.outputStream.Write(ProfileResolver.ExifMarker); // Write the exif data this.outputStream.Write(data, idx, bytesToWrite); remaining -= bytesToWrite; } }
public void IfdStructure() { var exif = new ExifProfile(); exif.SetValue(ExifTag.XPAuthor, "Dan Petitt"); Span <byte> actualBytes = exif.ToByteArray(); // Assert int ifdOffset = ExifConstants.LittleEndianByteOrderMarker.Length; Assert.Equal(8U, BinaryPrimitives.ReadUInt32LittleEndian(actualBytes.Slice(ifdOffset, 4))); int nextIfdPointerOffset = ExifConstants.LittleEndianByteOrderMarker.Length + 4 + 2 + 12; Assert.Equal(0U, BinaryPrimitives.ReadUInt32LittleEndian(actualBytes.Slice(nextIfdPointerOffset, 4))); }
public void ConstructorImageMetaData() { var metaData = new ImageMetaData(); var exifProfile = new ExifProfile(); var imageProperty = new ImageProperty("name", "value"); metaData.ExifProfile = exifProfile; metaData.HorizontalResolution = 4; metaData.VerticalResolution = 2; metaData.Properties.Add(imageProperty); ImageMetaData clone = metaData.DeepClone(); Assert.Equal(exifProfile.ToByteArray(), clone.ExifProfile.ToByteArray()); Assert.Equal(4, clone.HorizontalResolution); Assert.Equal(2, clone.VerticalResolution); Assert.Equal(imageProperty, clone.Properties[0]); }
public void Test_UnknownExifTag() { var exifProfile = new ExifProfile(); exifProfile.SetValue(ExifTag.ImageWidth, 42); var bytes = exifProfile.ToByteArray(); bytes[16] = 42; exifProfile = new ExifProfile(bytes); ExifTag unkownTag = (ExifTag)298; ExifValue value = exifProfile.GetValue(unkownTag); Assert.AreEqual(42, value.Value); Assert.AreEqual("42", value.ToString()); bytes = exifProfile.ToByteArray(); Assert.AreEqual(0, bytes.Length); }
public void ConstructorImageMetaData() { ImageMetaData metaData = new ImageMetaData(); ExifProfile exifProfile = new ExifProfile(); ImageProperty imageProperty = new ImageProperty("name", "value"); metaData.ExifProfile = exifProfile; metaData.HorizontalResolution = 4; metaData.VerticalResolution = 2; metaData.Properties.Add(imageProperty); metaData.RepeatCount = 1; ImageMetaData clone = new ImageMetaData(metaData); Assert.Equal(exifProfile.ToByteArray(), clone.ExifProfile.ToByteArray()); Assert.Equal(4, clone.HorizontalResolution); Assert.Equal(2, clone.VerticalResolution); Assert.Equal(imageProperty, clone.Properties[0]); Assert.Equal(1, clone.RepeatCount); }
public void ShouldReturnEmptyArrayWhenAllValuesAreInvalid() { var profile = new ExifProfile(); profile.SetValue(ExifTag.ImageWidth, 42); var bytes = profile.ToByteArray(); bytes[16] = 42; profile = new ExifProfile(bytes); var unkownTag = (ExifTag)298; var value = profile.GetValue(unkownTag); Assert.AreEqual(42, value.Value); Assert.AreEqual("42", value.ToString()); bytes = profile.ToByteArray(); Assert.AreEqual(0, bytes.Length); }
public void TestArrayValueWithUnspecifiedSize() { // This images contains array in the exif profile that has zero components. using Image <Rgba32> image = TestFile.Create(TestImages.Jpeg.Issues.InvalidCast520).CreateRgba32Image(); ExifProfile profile = image.Metadata.ExifProfile; Assert.NotNull(profile); // Force parsing of the profile. Assert.Equal(25, profile.Values.Count); // todo: duplicate tags (from root container and subIfd) Assert.Equal(2, profile.Values.Count(v => (ExifTagValue)(ushort)v.Tag == ExifTagValue.DateTime)); byte[] bytes = profile.ToByteArray(); Assert.Equal(525, bytes.Length); var profile2 = new ExifProfile(bytes); Assert.Equal(25, profile2.Values.Count); }
public void ProfileToByteArray() { // arrange byte[] exifBytesWithoutExifCode = ExifConstants.LittleEndianByteOrderMarker; ExifProfile expectedProfile = CreateExifProfile(); var expectedProfileTags = expectedProfile.Values.Select(x => x.Tag).ToList(); // act byte[] actualBytes = expectedProfile.ToByteArray(); var actualProfile = new ExifProfile(actualBytes); // assert Assert.NotNull(actualBytes); Assert.NotEmpty(actualBytes); Assert.Equal(exifBytesWithoutExifCode, actualBytes.Take(exifBytesWithoutExifCode.Length).ToArray()); foreach (ExifTag expectedProfileTag in expectedProfileTags) { ExifValue actualProfileValue = actualProfile.GetValue(expectedProfileTag); ExifValue expectedProfileValue = expectedProfile.GetValue(expectedProfileTag); Assert.Equal(expectedProfileValue.Value, actualProfileValue.Value); } }
public void ImageShouldAutoRotateInvalidValues <TPixel>(TestImageProvider <TPixel> provider, ExifDataType dataType, byte[] orientation) where TPixel : struct, IPixel <TPixel> { var profile = new ExifProfile(); profile.SetValue(ExifTag.JPEGTables, orientation); byte[] bytes = profile.ToByteArray(); // Change the tag into ExifTag.Orientation bytes[16] = 18; bytes[17] = 1; // Change the data type bytes[18] = (byte)dataType; // Change the number of components bytes[20] = 1; using (Image <TPixel> image = provider.GetImage()) { image.MetaData.ExifProfile = new ExifProfile(bytes); image.Mutate(x => x.AutoOrient()); } }