Skip to content

Commit

Permalink
IWP
Browse files Browse the repository at this point in the history
  • Loading branch information
qdraw committed Nov 13, 2024
1 parent e102ede commit d748b7a
Show file tree
Hide file tree
Showing 4 changed files with 224 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
using System.IO;
using File = TagLib.File;

namespace starsky.foundation.thumbnailmeta.Helpers;

public class TagLibSharpAbstractions
{
public class MemoryFileAbstraction : TagLib.File.IFileAbstraction
public class FileBytesAbstraction : File.IFileAbstraction
{
readonly Stream stream;

public MemoryFileAbstraction (Stream data)
public FileBytesAbstraction(string name, Stream stream)
{
stream = data;
Name = name;

ReadStream = stream;
WriteStream = stream;
}

public string Name => "MEMORY";
public void CloseStream(Stream stream)
{
stream.Dispose();
}

public Stream ReadStream => stream;
public string Name { get; }

public Stream WriteStream => stream;
public Stream ReadStream { get; }

public void CloseStream (Stream stream)
{
// This causes a stackoverflow
//stream?.Close();
}
public Stream WriteStream { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
using System;
using System.IO;
using System.Text;

public class SonyMakerNotesParser
{
public static void Main()
{
var imagePath = "your_image.jpg";
ParseSonyMakerNotes(imagePath);
}

public static void ParseSonyMakerNotes(string imagePath)
{
using ( var fs = new FileStream(imagePath, FileMode.Open, FileAccess.Read) )
using ( var reader = new BinaryReader(fs) )
{
if ( !IsJpeg(reader) )
{
Console.WriteLine("Not a valid JPEG file.");
return;
}

// Search for the APP1 (Exif) segment
while ( reader.BaseStream.Position < reader.BaseStream.Length )
{
var marker1 = reader.ReadByte();
var marker2 = reader.ReadByte();

// Check for known markers: APP1 (Exif), APP2 (Sony), etc.
if (marker1 == 0xFF)
{
// If it's APP1 or APP2 segment (common for Exif or Sony MakerNotes)
if (marker2 == 0xE1 || marker2 == 0xE2)
{
ushort segmentLength = ReadBigEndianUInt16(reader);
byte[] segmentData = reader.ReadBytes(segmentLength - 2);
Console.WriteLine($"Found Segment 0x{marker2:X2}, Length: {segmentLength}");

// Check for Exif or other known formats inside the segment
if (marker2 == 0xE1) // APP1 - Exif
{
Console.WriteLine("Found Exif Segment. Skipping.");
}
else if (marker2 == 0xE2) // APP2 - Sony MakerNotes
{
Console.WriteLine("Found Sony MakerNotes Segment.");
// Here you can further inspect the data
}
}
else
{
// Skip over other segments
ushort segmentLength = ReadBigEndianUInt16(reader);
reader.BaseStream.Seek(segmentLength - 2, SeekOrigin.Current);
}
}
else
{
// Skip over any non-marked sections
reader.BaseStream.Seek(1, SeekOrigin.Current);
}


// Check for APP1 (Exif) segment
if ( marker1 == 0xFF && marker2 == 0xE1 )
{
var segmentLength = ReadBigEndianUInt16(reader);
reader.BaseStream.Seek(segmentLength - 2,
SeekOrigin.Current); // Skip the rest of the segment

// Read Exif Header bytes
var exifHeader = reader.ReadBytes(6); // Read 6 bytes
Console.WriteLine("Exif Header (raw): " + BitConverter.ToString(exifHeader));

// Check for "Exif" in the header
if ( Encoding.ASCII.GetString(exifHeader, 0, 4) == "Exif" )
{
Console.WriteLine("Exif Header Found.");
// Parse TIFF header
reader.BaseStream.Seek(8, SeekOrigin.Current); // Skip TIFF header
var tagCount = ReadBigEndianUInt16(reader);

// Search for Sony's MakerNotes tag
for ( var i = 0; i < tagCount; i++ )
{
var tagId = ReadBigEndianUInt16(reader);
var tagType = ReadBigEndianUInt16(reader);
uint tagCountData = ReadBigEndianUInt16(reader);
uint tagValue = ReadBigEndianUInt16(reader);

// Check for MakerNotes or PreviewImage (Sony-specific tags)
if ( tagId == 0x927C ) // Sony MakerNotes tag ID
{
Console.WriteLine("Found MakerNotes.");
reader.BaseStream.Seek(tagValue,
SeekOrigin.Begin); // Seek to MakerNotes section

// Now manually process MakerNotes content
ParseMakerNotes(reader);
break; // Exit the loop after processing the MakerNotes
}
}
}

break; // Exit the loop after processing the Exif section
}
else
{
// Skip over other segments
var segmentLength = ReadBigEndianUInt16(reader);
reader.BaseStream.Seek(segmentLength - 2, SeekOrigin.Current);
}
}
}
}

private static void ParseMakerNotes(BinaryReader reader)
{
// Example parsing: Read and interpret Sony MakerNotes data
// Sony's MakerNotes may store preview image data in specific offsets, which you would need to find.

// Read bytes from the MakerNotes section only if there are enough bytes remaining
var remainingBytes = ( int ) ( reader.BaseStream.Length - reader.BaseStream.Position );
if ( remainingBytes > 0 )
{
var makerNotesData =
reader.ReadBytes(Math.Min(remainingBytes,
128)); // Read bytes, ensure not exceeding remaining stream length

// Inspect these bytes manually to see where the PreviewImage data might be stored
Console.WriteLine(BitConverter.ToString(makerNotesData, 0,
Math.Min(makerNotesData.Length, 64)));
}
else
{
Console.WriteLine("No data available to read from MakerNotes.");
}
}

private static bool IsJpeg(BinaryReader reader)
{
reader.BaseStream.Seek(0, SeekOrigin.Begin);
return reader.ReadByte() == 0xFF && reader.ReadByte() == 0xD8;
}

private static ushort ReadBigEndianUInt16(BinaryReader reader)
{
if ( reader.BaseStream.Position + 2 <= reader.BaseStream.Length )
{
var highByte = reader.ReadByte();
var lowByte = reader.ReadByte();
return ( ushort ) ( ( highByte << 8 ) | lowByte );
}

throw new EndOfStreamException("Unable to read beyond the end of the stream.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using MetadataExtractor;
using MetadataExtractor.Formats.Exif;
using MetadataExtractor.Formats.Exif.Makernotes;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using starsky.foundation.platform.Helpers;
using starsky.foundation.platform.Interfaces;
using starsky.foundation.storage.Interfaces;
Expand Down Expand Up @@ -100,9 +105,53 @@ public List<Directory> ReadExifMetaDirectory(string subPath)
private (bool offsetSuccess, int offset, bool byteSizeSuccess, int byteSize)
GetOffsetAndByteSizeForJpeg(string subPath)
{
var file = TagLib.File.Create(new TagLibSharpAbstractions.MemoryFileAbstraction(_iStorage.ReadStream(subPath)));
var directories = ImageMetadataReader.ReadMetadata(
"/Users/dion/data/fotobieb/2024/11/2024_11_11_d/20241111_181721_DSC00782.jpg");
var directory = directories.OfType<SonyType1MakernoteDirectory>().FirstOrDefault();

SonyMakerNotesParser.ParseSonyMakerNotes(
"/Users/dion/data/fotobieb/2024/11/2024_11_11_d/20241111_181721_DSC00782.jpg");

return ( false, 0, false, 0 );

// Check if directory contains PreviewImage tag (0x2001)
var previewImageTag = directory.GetObject(0x2001);
if ( previewImageTag is byte[] previewImageData )
{
System.IO.File.WriteAllBytes("/tmp/sony_preview_image.jpg", previewImageData);
Console.WriteLine(
"Sony preview image extracted successfully to 'sony_preview_image.jpg'.");
}
else
{
Console.WriteLine("Preview image tag not found in Sony MakerNotes.");
}

using ( var image = Image.Load(_iStorage.ReadStream(subPath)) )
{
var exifProfile = image.Metadata.ExifProfile;
if ( exifProfile != null )
{
var makerNote = exifProfile.Values.FirstOrDefault(p => p.Tag == ExifTag.MakerNote)
?.GetValue() as byte[];
var str = Encoding.Default.GetString(makerNote);
// Access Exif tags
Console.WriteLine();
}
}


var file =
File.Create(new TagLibSharpAbstractions.FileBytesAbstraction("test.jpg",
_iStorage.ReadStream(subPath)));
var t = file.Tag;

var json = JsonSerializer.Serialize(t,
new JsonSerializerOptions
{
WriteIndented = true,
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals
});

// var test = new PreviewImageExtractor().GetImageSize(
// "/Users/dion/data/git/starsky/starsky/starskytest/FakeCreateAn/CreateAnImageLargePreview/20241112_110839_DSC02741.jpg");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public async Task NoThumbnail_InMemoryIntegration()
[DataRow("/A6600.arw", "preview_image2", 1000, 668)]
[DataRow("/poppy.jpg", "preview_image3", 1000, 120)]
[DataRow("/13mini.jpg", "preview_image4", 1000, 668)]
[Timeout(5000)]
public async Task Image_WithThumbnail_InMemoryIntegrationTest(string subPath, string hash,
int expectedWidth, int expectedHeight)
{
Expand Down

0 comments on commit d748b7a

Please sign in to comment.