public virtual void TestGetInt64() { sbyte[] buffer = new sbyte[] { unchecked ((int)(0x00)), unchecked ((int)(0x01)), unchecked ((int)(0x02)), unchecked ((int)(0x03)), unchecked ((int)(0x04)), unchecked ((int)(0x05)), unchecked ((int)(0x06)), unchecked ( (int)(0x07)), unchecked ((sbyte)unchecked ((int)(0xFF))) }; RandomAccessReader reader = CreateReader(buffer); Sharpen.Tests.AreEqual(unchecked ((long)(0x0001020304050607L)), reader.GetInt64(0)); Sharpen.Tests.AreEqual(unchecked ((long)(0x01020304050607FFL)), reader.GetInt64(1)); reader.SetMotorolaByteOrder(false); Sharpen.Tests.AreEqual(unchecked ((long)(0x0706050403020100L)), reader.GetInt64(0)); Sharpen.Tests.AreEqual(unchecked ((long)(0xFF07060504030201L)), reader.GetInt64(1)); }
public virtual void TestGetUInt16() { sbyte[] buffer = new sbyte[] { unchecked ((int)(0x00)), unchecked ((int)(0x01)), unchecked ((sbyte)unchecked ((int)(0x7F))), unchecked ((sbyte)unchecked ((int)(0xFF))) }; RandomAccessReader reader = CreateReader(buffer); Sharpen.Tests.AreEqual(unchecked ((int)(0x0001)), reader.GetUInt16(0)); Sharpen.Tests.AreEqual(unchecked ((int)(0x017F)), reader.GetUInt16(1)); Sharpen.Tests.AreEqual(unchecked ((int)(0x7FFF)), reader.GetUInt16(2)); reader.SetMotorolaByteOrder(false); Sharpen.Tests.AreEqual(unchecked ((int)(0x0100)), reader.GetUInt16(0)); Sharpen.Tests.AreEqual(unchecked ((int)(0x7F01)), reader.GetUInt16(1)); Sharpen.Tests.AreEqual(unchecked ((int)(0xFF7F)), reader.GetUInt16(2)); }
/// <summary>Processes a TIFF data sequence.</summary> /// <param name="reader"> /// the /// <see cref="Com.Drew.Lang.RandomAccessReader"/> /// from which the data should be read /// </param> /// <param name="handler"> /// the /// <see cref="TiffHandler"/> /// that will coordinate processing and accept read values /// </param> /// <param name="tiffHeaderOffset">the offset within <code>reader</code> at which the TIFF header starts</param> /// <exception cref="TiffProcessingException"> /// if an error occurred during the processing of TIFF data that could not be /// ignored or recovered from /// </exception> /// <exception cref="System.IO.IOException">an error occurred while accessing the required data</exception> /// <exception cref="Com.Drew.Imaging.Tiff.TiffProcessingException"/> public virtual void ProcessTiff(RandomAccessReader reader, TiffHandler handler, int tiffHeaderOffset) { // This must be either "MM" or "II". short byteOrderIdentifier = reader.GetInt16(tiffHeaderOffset); if (byteOrderIdentifier == unchecked((int)(0x4d4d))) { // "MM" reader.SetMotorolaByteOrder(true); } else { if (byteOrderIdentifier == unchecked((int)(0x4949))) { // "II" reader.SetMotorolaByteOrder(false); } else { throw new TiffProcessingException("Unclear distinction between Motorola/Intel byte ordering: " + byteOrderIdentifier); } } // Check the next two values for correctness. int tiffMarker = reader.GetUInt16(2 + tiffHeaderOffset); handler.SetTiffMarker(tiffMarker); int firstIfdOffset = reader.GetInt32(4 + tiffHeaderOffset) + tiffHeaderOffset; // David Ekholm sent a digital camera image that has this problem // TODO getLength should be avoided as it causes RandomAccessStreamReader to read to the end of the stream if (firstIfdOffset >= reader.GetLength() - 1) { handler.Warn("First IFD offset is beyond the end of the TIFF data segment -- trying default offset"); // First directory normally starts immediately after the offset bytes, so try that firstIfdOffset = tiffHeaderOffset + 2 + 2 + 4; } ICollection<int> processedIfdOffsets = new HashSet<int>(); ProcessIfd(handler, reader, processedIfdOffsets, firstIfdOffset, tiffHeaderOffset); handler.Completed(reader, tiffHeaderOffset); }
public virtual void TestGetUInt32() { Sharpen.Tests.AreEqual(4294967295L, CreateReader(new sbyte[] { unchecked ((sbyte)0xff), unchecked ((sbyte)0xff), unchecked ((sbyte)0xff), unchecked ((sbyte)0xff) }).GetUInt32(0)); sbyte[] buffer = new sbyte[] { unchecked ((int)(0x00)), unchecked ((int)(0x01)), unchecked ((sbyte)0x7F), unchecked ((sbyte)0xFF), unchecked ((int)(0x02)), unchecked ((int)(0x03)), unchecked ((int)(0x04)) }; RandomAccessReader reader = CreateReader(buffer); Sharpen.Tests.AreEqual(unchecked ((long)(0x00017FFFL)), reader.GetUInt32(0)); Sharpen.Tests.AreEqual(unchecked ((long)(0x017FFF02L)), reader.GetUInt32(1)); Sharpen.Tests.AreEqual(unchecked ((long)(0x7FFF0203L)), reader.GetUInt32(2)); Sharpen.Tests.AreEqual(unchecked ((long)(0xFF020304L)), reader.GetUInt32(3)); reader.SetMotorolaByteOrder(false); Sharpen.Tests.AreEqual(4286513408L, reader.GetUInt32(0)); Sharpen.Tests.AreEqual(unchecked ((long)(0x02FF7F01L)), reader.GetUInt32(1)); Sharpen.Tests.AreEqual(unchecked ((long)(0x0302FF7FL)), reader.GetUInt32(2)); Sharpen.Tests.AreEqual(unchecked ((long)(0x040302FFL)), reader.GetInt32(3)); }
public virtual void TestGetInt32() { Sharpen.Tests.AreEqual(-1, CreateReader(new sbyte[] { unchecked ((sbyte)unchecked ((int)(0xff))), unchecked ((sbyte)unchecked ((int)(0xff))), unchecked ((sbyte)unchecked ((int)(0xff))), unchecked ((sbyte )unchecked ((int)(0xff))) }).GetInt32(0)); sbyte[] buffer = new sbyte[] { unchecked ((int)(0x00)), unchecked ((int)(0x01)), unchecked ((sbyte)unchecked ((int)(0x7F))), unchecked ((sbyte)unchecked ((int)(0xFF))), unchecked ((int)(0x02)), unchecked ((int )(0x03)), unchecked ((int)(0x04)) }; RandomAccessReader reader = CreateReader(buffer); Sharpen.Tests.AreEqual(unchecked ((int)(0x00017FFF)), reader.GetInt32(0)); Sharpen.Tests.AreEqual(unchecked ((int)(0x017FFF02)), reader.GetInt32(1)); Sharpen.Tests.AreEqual(unchecked ((int)(0x7FFF0203)), reader.GetInt32(2)); Sharpen.Tests.AreEqual(unchecked ((int)(0xFF020304)), reader.GetInt32(3)); reader.SetMotorolaByteOrder(false); Sharpen.Tests.AreEqual(unchecked ((int)(0xFF7F0100)), reader.GetInt32(0)); Sharpen.Tests.AreEqual(unchecked ((int)(0x02FF7F01)), reader.GetInt32(1)); Sharpen.Tests.AreEqual(unchecked ((int)(0x0302FF7F)), reader.GetInt32(2)); Sharpen.Tests.AreEqual(unchecked ((int)(0x040302FF)), reader.GetInt32(3)); }
private static void ProcessMakernote(int makernoteOffset, ICollection<int> processedIfdOffsets, int tiffHeaderOffset, Com.Drew.Metadata.Metadata metadata, RandomAccessReader reader) { // Determine the camera model and makernote format Com.Drew.Metadata.Directory ifd0Directory = metadata.GetDirectory<ExifIFD0Directory>(); if (ifd0Directory == null) { return; } string cameraMake = ifd0Directory.GetString(ExifIFD0Directory.TagMake); string firstThreeChars = reader.GetString(makernoteOffset, 3); string firstFourChars = reader.GetString(makernoteOffset, 4); string firstFiveChars = reader.GetString(makernoteOffset, 5); string firstSixChars = reader.GetString(makernoteOffset, 6); string firstSevenChars = reader.GetString(makernoteOffset, 7); string firstEightChars = reader.GetString(makernoteOffset, 8); string firstTwelveChars = reader.GetString(makernoteOffset, 12); bool byteOrderBefore = reader.IsMotorolaByteOrder(); if ("OLYMP".Equals(firstFiveChars) || "EPSON".Equals(firstFiveChars) || "AGFA".Equals(firstFourChars)) { // Olympus Makernote // Epson and Agfa use Olympus makernote standard: http://www.ozhiker.com/electronics/pjmt/jpeg_info/ ProcessIFD(metadata.GetOrCreateDirectory<OlympusMakernoteDirectory>(), processedIfdOffsets, makernoteOffset + 8, tiffHeaderOffset, metadata, reader); } else { if (cameraMake != null && Sharpen.Extensions.Trim(cameraMake).ToUpper().StartsWith("NIKON")) { if ("Nikon".Equals(firstFiveChars)) { switch (reader.GetUInt8(makernoteOffset + 6)) { case 1: { /* There are two scenarios here: * Type 1: ** * :0000: 4E 69 6B 6F 6E 00 01 00-05 00 02 00 02 00 06 00 Nikon........... * :0010: 00 00 EC 02 00 00 03 00-03 00 01 00 00 00 06 00 ................ * Type 3: ** * :0000: 4E 69 6B 6F 6E 00 02 00-00 00 4D 4D 00 2A 00 00 Nikon....MM.*... * :0010: 00 08 00 1E 00 01 00 07-00 00 00 04 30 32 30 30 ............0200 */ ProcessIFD(metadata.GetOrCreateDirectory<NikonType1MakernoteDirectory>(), processedIfdOffsets, makernoteOffset + 8, tiffHeaderOffset, metadata, reader); break; } case 2: { ProcessIFD(metadata.GetOrCreateDirectory<NikonType2MakernoteDirectory>(), processedIfdOffsets, makernoteOffset + 18, makernoteOffset + 10, metadata, reader); break; } default: { ifd0Directory.AddError("Unsupported Nikon makernote data ignored."); break; } } } else { // The IFD begins with the first Makernote byte (no ASCII name). This occurs with CoolPix 775, E990 and D1 models. ProcessIFD(metadata.GetOrCreateDirectory<NikonType2MakernoteDirectory>(), processedIfdOffsets, makernoteOffset, tiffHeaderOffset, metadata, reader); } } else { if ("SONY CAM".Equals(firstEightChars) || "SONY DSC".Equals(firstEightChars)) { ProcessIFD(metadata.GetOrCreateDirectory<SonyType1MakernoteDirectory>(), processedIfdOffsets, makernoteOffset + 12, tiffHeaderOffset, metadata, reader); } else { if ("SEMC MS\u0000\u0000\u0000\u0000\u0000".Equals(firstTwelveChars)) { // force MM for this directory reader.SetMotorolaByteOrder(true); // skip 12 byte header + 2 for "MM" + 6 ProcessIFD(metadata.GetOrCreateDirectory<SonyType6MakernoteDirectory>(), processedIfdOffsets, makernoteOffset + 20, tiffHeaderOffset, metadata, reader); } else { if ("SIGMA\u0000\u0000\u0000".Equals(firstEightChars) || "FOVEON\u0000\u0000".Equals(firstEightChars)) { ProcessIFD(metadata.GetOrCreateDirectory<SigmaMakernoteDirectory>(), processedIfdOffsets, makernoteOffset + 10, tiffHeaderOffset, metadata, reader); } else { if ("KDK".Equals(firstThreeChars)) { reader.SetMotorolaByteOrder(firstSevenChars.Equals("KDK INFO")); ProcessKodakMakernote(metadata.GetOrCreateDirectory<KodakMakernoteDirectory>(), makernoteOffset, reader); } else { if (Sharpen.Runtime.EqualsIgnoreCase("Canon", cameraMake)) { ProcessIFD(metadata.GetOrCreateDirectory<CanonMakernoteDirectory>(), processedIfdOffsets, makernoteOffset, tiffHeaderOffset, metadata, reader); } else { if (cameraMake != null && cameraMake.ToUpper().StartsWith("CASIO")) { if ("QVC\u0000\u0000\u0000".Equals(firstSixChars)) { ProcessIFD(metadata.GetOrCreateDirectory<CasioType2MakernoteDirectory>(), processedIfdOffsets, makernoteOffset + 6, tiffHeaderOffset, metadata, reader); } else { ProcessIFD(metadata.GetOrCreateDirectory<CasioType1MakernoteDirectory>(), processedIfdOffsets, makernoteOffset, tiffHeaderOffset, metadata, reader); } } else { if ("FUJIFILM".Equals(firstEightChars) || Sharpen.Runtime.EqualsIgnoreCase("Fujifilm", cameraMake)) { // Note that this also applies to certain Leica cameras, such as the Digilux-4.3 reader.SetMotorolaByteOrder(false); // the 4 bytes after "FUJIFILM" in the makernote point to the start of the makernote // IFD, though the offset is relative to the start of the makernote, not the TIFF // header (like everywhere else) int ifdStart = makernoteOffset + reader.GetInt32(makernoteOffset + 8); ProcessIFD(metadata.GetOrCreateDirectory<FujifilmMakernoteDirectory>(), processedIfdOffsets, ifdStart, makernoteOffset, metadata, reader); } else { if (cameraMake != null && cameraMake.ToUpper().StartsWith("MINOLTA")) { // Cases seen with the model starting with MINOLTA in capitals seem to have a valid Olympus makernote // area that commences immediately. ProcessIFD(metadata.GetOrCreateDirectory<OlympusMakernoteDirectory>(), processedIfdOffsets, makernoteOffset, tiffHeaderOffset, metadata, reader); } else { if ("KYOCERA".Equals(firstSevenChars)) { // http://www.ozhiker.com/electronics/pjmt/jpeg_info/kyocera_mn.html ProcessIFD(metadata.GetOrCreateDirectory<KyoceraMakernoteDirectory>(), processedIfdOffsets, makernoteOffset + 22, tiffHeaderOffset, metadata, reader); } else { if ("LEICA".Equals(firstFiveChars)) { reader.SetMotorolaByteOrder(false); if ("Leica Camera AG".Equals(cameraMake)) { ProcessIFD(metadata.GetOrCreateDirectory<LeicaMakernoteDirectory>(), processedIfdOffsets, makernoteOffset + 8, tiffHeaderOffset, metadata, reader); } else { if ("LEICA".Equals(cameraMake)) { // Some Leica cameras use Panasonic makernote tags ProcessIFD(metadata.GetOrCreateDirectory<PanasonicMakernoteDirectory>(), processedIfdOffsets, makernoteOffset + 8, tiffHeaderOffset, metadata, reader); } } } else { if ("Panasonic\u0000\u0000\u0000".Equals(reader.GetString(makernoteOffset, 12))) { // NON-Standard TIFF IFD Data using Panasonic Tags. There is no Next-IFD pointer after the IFD // Offsets are relative to the start of the TIFF header at the beginning of the EXIF segment // more information here: http://www.ozhiker.com/electronics/pjmt/jpeg_info/panasonic_mn.html ProcessIFD(metadata.GetOrCreateDirectory<PanasonicMakernoteDirectory>(), processedIfdOffsets, makernoteOffset + 12, tiffHeaderOffset, metadata, reader); } else { if ("AOC\u0000".Equals(firstFourChars)) { // NON-Standard TIFF IFD Data using Casio Type 2 Tags // IFD has no Next-IFD pointer at end of IFD, and // Offsets are relative to the start of the current IFD tag, not the TIFF header // Observed for: // - Pentax ist D ProcessIFD(metadata.GetOrCreateDirectory<CasioType2MakernoteDirectory>(), processedIfdOffsets, makernoteOffset + 6, makernoteOffset, metadata, reader); } else { if (cameraMake != null && (cameraMake.ToUpper().StartsWith("PENTAX") || cameraMake.ToUpper().StartsWith("ASAHI"))) { // NON-Standard TIFF IFD Data using Pentax Tags // IFD has no Next-IFD pointer at end of IFD, and // Offsets are relative to the start of the current IFD tag, not the TIFF header // Observed for: // - PENTAX Optio 330 // - PENTAX Optio 430 ProcessIFD(metadata.GetOrCreateDirectory<PentaxMakernoteDirectory>(), processedIfdOffsets, makernoteOffset, makernoteOffset, metadata, reader); } else { // } else if ("KC".equals(firstTwoChars) || "MINOL".equals(firstFiveChars) || "MLY".equals(firstThreeChars) || "+M+M+M+M".equals(firstEightChars)) { // // This Konica data is not understood. Header identified in accordance with information at this site: // // http://www.ozhiker.com/electronics/pjmt/jpeg_info/minolta_mn.html // // TODO add support for minolta/konica cameras // exifDirectory.addError("Unsupported Konica/Minolta data ignored."); if ("SANYO\x0\x1\x0".Equals(firstEightChars)) { ProcessIFD(metadata.GetOrCreateDirectory<SanyoMakernoteDirectory>(), processedIfdOffsets, makernoteOffset + 8, makernoteOffset, metadata, reader); } } } } } } } } } } } } } } } } // The makernote is not comprehended by this library. // If you are reading this and believe a particular camera's image should be processed, get in touch. reader.SetMotorolaByteOrder(byteOrderBefore); }
private static void ExtractTiff(RandomAccessReader reader, Com.Drew.Metadata.Metadata metadata, Com.Drew.Metadata.Directory firstDirectory, int tiffHeaderOffset) { // this should be either "MM" or "II" string byteOrderIdentifier = reader.GetString(tiffHeaderOffset, 2); if ("MM".Equals(byteOrderIdentifier)) { reader.SetMotorolaByteOrder(true); } else { if ("II".Equals(byteOrderIdentifier)) { reader.SetMotorolaByteOrder(false); } else { firstDirectory.AddError("Unclear distinction between Motorola/Intel byte ordering: " + byteOrderIdentifier); return; } } // Check the next two values for correctness. int tiffMarker = reader.GetUInt16(2 + tiffHeaderOffset); int standardTiffMarker = unchecked((int)(0x002A)); int olympusRawTiffMarker = unchecked((int)(0x4F52)); // for ORF files int panasonicRawTiffMarker = unchecked((int)(0x0055)); // for RW2 files if (tiffMarker != standardTiffMarker && tiffMarker != olympusRawTiffMarker && tiffMarker != panasonicRawTiffMarker) { firstDirectory.AddError("Unexpected TIFF marker after byte order identifier: 0x" + Sharpen.Extensions.ToHexString(tiffMarker)); return; } int firstIfdOffset = reader.GetInt32(4 + tiffHeaderOffset) + tiffHeaderOffset; // David Ekholm sent a digital camera image that has this problem // TODO getLength should be avoided as it causes RandomAccessStreamReader to read to the end of the stream if (firstIfdOffset >= reader.GetLength() - 1) { firstDirectory.AddError("First Exif directory offset is beyond end of Exif data segment"); // First directory normally starts 14 bytes in -- try it here and catch another error in the worst case firstIfdOffset = 14; } ICollection<int> processedIfdOffsets = new HashSet<int>(); ProcessIFD(firstDirectory, processedIfdOffsets, firstIfdOffset, tiffHeaderOffset, metadata, reader); // after the extraction process, if we have the correct tags, we may be able to store thumbnail information ExifThumbnailDirectory thumbnailDirectory = metadata.GetDirectory<ExifThumbnailDirectory>(); if (thumbnailDirectory != null && thumbnailDirectory.ContainsTag(ExifThumbnailDirectory.TagThumbnailCompression)) { int? offset = thumbnailDirectory.GetInteger(ExifThumbnailDirectory.TagThumbnailOffset); int? length = thumbnailDirectory.GetInteger(ExifThumbnailDirectory.TagThumbnailLength); if (offset != null && length != null) { try { sbyte[] thumbnailData = reader.GetBytes(tiffHeaderOffset + offset.Value, length.Value); thumbnailDirectory.SetThumbnailData(thumbnailData); } catch (IOException ex) { firstDirectory.AddError("Invalid thumbnail data specification: " + ex.Message); } } } }