Skip to content

Commit

Permalink
One can now add, remove and update embedded pictures using the Track …
Browse files Browse the repository at this point in the history
…class
  • Loading branch information
Zeugma440 committed Oct 22, 2017
1 parent d4276a4 commit 45b575d
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 11 deletions.
97 changes: 96 additions & 1 deletion ATL.test/IO/HighLevel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ATL.AudioData;
using System.IO;
using System.Drawing;

namespace ATL.test.IO
{
Expand Down Expand Up @@ -109,7 +110,7 @@ public void TagIO_RW_UpdateTagBaseField()
}

[TestMethod]
public void TagIO_RW_UpdateTagAdditionalField()
public void TagIO_RW_AddRemoveTagAdditionalField()
{
string testFileLocation = TestUtils.GetTempTestFile("MP3/01 - Title Screen.mp3");
Track theTrack = new Track(testFileLocation);
Expand All @@ -128,6 +129,100 @@ public void TagIO_RW_UpdateTagAdditionalField()
File.Delete(testFileLocation);
}

[TestMethod]
public void TagIO_RW_UpdateTagAdditionalField()
{
string testFileLocation = TestUtils.GetTempTestFile("MP3/01 - Title Screen.mp3");
Track theTrack = new Track(testFileLocation);

theTrack.AdditionalFields["TENC"] = "update test";
theTrack.Save();

theTrack = new Track(testFileLocation);

Assert.AreEqual(1, theTrack.AdditionalFields.Count);
Assert.IsTrue(theTrack.AdditionalFields.ContainsKey("TENC"));
Assert.AreEqual("update test", theTrack.AdditionalFields["TENC"]);

// Get rid of the working copy
File.Delete(testFileLocation);
}

[TestMethod]
public void TagIO_RW_AddRemoveTagPictures()
{
string testFileLocation = TestUtils.GetTempTestFile("MP3/id3v2.4_UTF8.mp3");
Track theTrack = new Track(testFileLocation);

theTrack.EmbeddedPictures.RemoveAt(1); // Remove Conductor; Front Cover remains

// Add CD
TagData.PictureInfo newPicture = new TagData.PictureInfo(Commons.ImageFormat.Gif, TagData.PIC_TYPE.CD);
newPicture.PictureData = File.ReadAllBytes(TestUtils.GetResourceLocationRoot() + "_Images/pic1.gif");
theTrack.EmbeddedPictures.Add(newPicture);

theTrack.Save();

theTrack = new Track(testFileLocation);

Assert.AreEqual(2, theTrack.EmbeddedPictures.Count); // Front Cover, CD

bool foundFront = false;
bool foundCD = false;

foreach (TagData.PictureInfo pic in theTrack.EmbeddedPictures)
{
if (pic.PicType.Equals(TagData.PIC_TYPE.Front)) foundFront = true;
if (pic.PicType.Equals(TagData.PIC_TYPE.CD)) foundCD = true;
}

Assert.IsTrue(foundFront);
Assert.IsTrue(foundCD);

// Get rid of the working copy
File.Delete(testFileLocation);
}

[TestMethod]
public void TagIO_RW_UpdateTagPictures()
{
string testFileLocation = TestUtils.GetTempTestFile("MP3/id3v2.4_UTF8.mp3");
Track theTrack = new Track(testFileLocation);

// Update Front picture
TagData.PictureInfo newPicture = new TagData.PictureInfo(Commons.ImageFormat.Jpeg, TagData.PIC_TYPE.Front);
newPicture.PictureData = File.ReadAllBytes(TestUtils.GetResourceLocationRoot() + "_Images/pic2.jpg");
theTrack.EmbeddedPictures.Add(newPicture);

theTrack.Save();

theTrack = new Track(testFileLocation);

Assert.AreEqual(2, theTrack.EmbeddedPictures.Count); // Front Cover, Conductor

bool foundFront = false;
bool foundConductor = false;

foreach (TagData.PictureInfo pic in theTrack.EmbeddedPictures)
{
if (pic.PicType.Equals(TagData.PIC_TYPE.Front))
{
foundFront = true;
Image picture = Image.FromStream(new MemoryStream(pic.PictureData));
Assert.AreEqual(picture.RawFormat, System.Drawing.Imaging.ImageFormat.Jpeg);
Assert.AreEqual(picture.Width, 900);
Assert.AreEqual(picture.Height, 290);
}
if (pic.PicType.Equals(TagData.PIC_TYPE.Unsupported)) foundConductor = true;
}

Assert.IsTrue(foundFront);
Assert.IsTrue(foundConductor);

// Get rid of the working copy
File.Delete(testFileLocation);
}

[TestMethod]
public void TagIO_RW_UpdateKeepDataIntegrity()
{
Expand Down
17 changes: 17 additions & 0 deletions ATL/Entities/TagData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,28 @@ public class PictureInfo
// TODO - add a description field

public byte[] PictureData; // Binary picture data
public uint PictureHash; // Hash of binary picture data

public bool MarkedForDeletion = false; // True if the field has to be deleted in the next IMetaDataIO.Write operation
public int Flag; // Freeform value to be used by other parts of the library

// ---------------- CONSTRUCTORS

public PictureInfo(PictureInfo picInfo)
{
this.PicType = picInfo.PicType;
this.NativeFormat = picInfo.NativeFormat;
this.Position = picInfo.Position;
this.TagType = picInfo.TagType;
this.NativePicCode = picInfo.NativePicCode;
this.NativePicCodeStr = picInfo.NativePicCodeStr;
if (picInfo.PictureData != null)
{
this.PictureData = new byte[picInfo.PictureData.Length];
picInfo.PictureData.CopyTo(this.PictureData, 0);
}
this.MarkedForDeletion = picInfo.MarkedForDeletion;
}
public PictureInfo(ImageFormat nativeFormat, PIC_TYPE picType, int tagType, object nativePicCode, int position = 1)
{
PicType = picType; NativeFormat = nativeFormat; TagType = tagType; Position = position;
Expand Down
83 changes: 73 additions & 10 deletions ATL/Entities/Track.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,14 @@ public Track(string iPath)
public int TrackNumber;
public int DiscNumber;
public int Rating;
public IDictionary<string, string> AdditionalFields;
private ICollection<string> InitialAdditionalFields; // Initial fields, to track removed ones
public IList<TagData.PictureInfo> PictureTokens = null;

public IDictionary<string, string> AdditionalFields;
private ICollection<string> initialAdditionalFields; // Initial fields, used to identify removed ones

private IList<TagData.PictureInfo> embeddedPictures = null;
private ICollection<TagData.PictureInfo> initialEmbeddedPictures; // Initial fields, used to identify removed ones

private AudioFileIO fileIO;


Expand All @@ -65,6 +68,7 @@ public IList<TagData.PictureInfo> EmbeddedPictures
if (null == embeddedPictures)
{
embeddedPictures = new List<TagData.PictureInfo>();
initialEmbeddedPictures = new List<TagData.PictureInfo>();

Update(new TagData.PictureStreamHandlerDelegate(readBinaryImageData));
}
Expand All @@ -77,7 +81,12 @@ protected void readBinaryImageData(ref MemoryStream s, TagData.PIC_TYPE picType,
TagData.PictureInfo picInfo = new TagData.PictureInfo(imgFormat, picType, originalTag, picCode, position);
picInfo.PictureData = s.ToArray();

// Initial pic info, without picture data
TagData.PictureInfo initialPicInfo = new TagData.PictureInfo(imgFormat, picType, originalTag, picCode, position);
initialPicInfo.PictureHash = HashDepot.Fnv1a.Hash32(picInfo.PictureData);

embeddedPictures.Add(picInfo);
initialEmbeddedPictures.Add(initialPicInfo);
}

protected void Update(TagData.PictureStreamHandlerDelegate pictureStreamHandler = null)
Expand All @@ -101,8 +110,6 @@ protected void Update(TagData.PictureStreamHandlerDelegate pictureStreamHandler
Publisher = Utils.ProtectValue(fileIO.Publisher);
AlbumArtist = Utils.ProtectValue(fileIO.AlbumArtist);
Conductor = Utils.ProtectValue(fileIO.Conductor);
AdditionalFields = fileIO.AdditionalFields; // ???
InitialAdditionalFields = fileIO.AdditionalFields.Keys;
Year = fileIO.IntYear;
Album = fileIO.Album;
TrackNumber = fileIO.Track;
Expand All @@ -113,12 +120,18 @@ protected void Update(TagData.PictureStreamHandlerDelegate pictureStreamHandler
Rating = fileIO.Rating;
IsVBR = fileIO.IsVBR;
SampleRate = fileIO.SampleRate;

AdditionalFields = fileIO.AdditionalFields;
initialAdditionalFields = fileIO.AdditionalFields.Keys;

PictureTokens = new List<TagData.PictureInfo>(fileIO.PictureTokens);

if (null == pictureStreamHandler && embeddedPictures != null)
{
embeddedPictures.Clear();
initialEmbeddedPictures.Clear();
embeddedPictures = null;
initialEmbeddedPictures = null;
}
}

Expand All @@ -143,21 +156,71 @@ private TagData toTagData()
result.TrackNumber = TrackNumber.ToString();
result.DiscNumber = DiscNumber.ToString();
result.Rating = Rating.ToString();
result.Pictures = embeddedPictures;

foreach (string s in AdditionalFields.Keys)
{
result.AdditionalFields.Add(new TagData.MetaFieldInfo(MetaDataIOFactory.TAG_ANY, s, AdditionalFields[s]));
}

// Detect and tag deleted Additional fields
foreach (string s in InitialAdditionalFields)
// Detect and tag deleted Additional fields (=those which were in initialAdditionalFields and do not appear in AdditionalFields anymore)
foreach (string s in initialAdditionalFields)
{
if (!AdditionalFields.ContainsKey(s))
{
TagData.MetaFieldInfo metaField = new TagData.MetaFieldInfo(MetaDataIOFactory.TAG_ANY, s, "");
metaField.MarkedForDeletion = true;
result.AdditionalFields.Add(metaField);
TagData.MetaFieldInfo metaFieldToDelete = new TagData.MetaFieldInfo(MetaDataIOFactory.TAG_ANY, s, "");
metaFieldToDelete.MarkedForDeletion = true;
result.AdditionalFields.Add(metaFieldToDelete);
}
}

result.Pictures = new List<TagData.PictureInfo>();
if (embeddedPictures != null) foreach (TagData.PictureInfo targetPic in embeddedPictures) targetPic.Flag = 0;

if (initialEmbeddedPictures != null)
{
foreach (TagData.PictureInfo picInfo in initialEmbeddedPictures)
{
// Detect and tag deleted pictures (=those which were in initialEmbeddedPictures and do not appear in embeddedPictures anymore)
if (!embeddedPictures.Contains(picInfo))
{
TagData.PictureInfo picToDelete = new TagData.PictureInfo(picInfo);
picToDelete.MarkedForDeletion = true;
result.Pictures.Add(picToDelete);
}
else // Only add new additions (pictures identical to initial list will be kept, and do not have to make it to the list, or else a duplicate will be created)
{
foreach (TagData.PictureInfo targetPic in embeddedPictures)
{
if (targetPic.Equals(picInfo))
{
// Compare picture contents
uint newPictureHash = HashDepot.Fnv1a.Hash32(targetPic.PictureData);

if (newPictureHash != picInfo.PictureHash)
{
// A new picture content has been defined for an existing location
result.Pictures.Add(targetPic);

TagData.PictureInfo picToDelete = new TagData.PictureInfo(picInfo);
picToDelete.MarkedForDeletion = true;
result.Pictures.Add(picToDelete);
}

targetPic.Flag = 1;
}
}
}
}

if (embeddedPictures != null)
{
foreach (TagData.PictureInfo targetPic in embeddedPictures)
{
if (0 == targetPic.Flag) // Entirely new pictures without equivalent in initialEmbeddedPictures
{
result.Pictures.Add(targetPic);
}
}
}
}

Expand Down

0 comments on commit 45b575d

Please sign in to comment.