![]() |
Sylloge
A C# helper library
|
00001 using System; 00002 using System.Collections.Generic; 00003 using System.Linq; 00004 using System.Text; 00005 00006 namespace Sylloge.Audio.Metadata.ID3.Frames 00007 { 00008 public class AttachedPicture : TextFrame 00009 { 00013 public byte[] ImageData { get; private set; } 00017 public string MimeType { get; private set; } 00021 public Picture Type { get; private set; } 00022 00023 public AttachedPicture() 00024 : base(ID3.Frame.Keys.AttachedPicture) 00025 { 00026 this.Initialize(0x00, string.Empty, string.Empty, Picture.Other, null); 00027 } 00028 00029 public AttachedPicture(System.Drawing.Image img) 00030 : base(ID3.Frame.Keys.AttachedPicture) 00031 { 00032 this.Initialize(img, Picture.Other); 00033 } 00034 00035 public AttachedPicture(System.Drawing.Image img, Picture type) 00036 : base(ID3.Frame.Keys.AttachedPicture) 00037 { 00038 this.Initialize(img, type); 00039 } 00040 00041 public AttachedPicture(Frame other) 00042 : base(other) 00043 { 00044 if (other.ID != ID3.Frame.Keys.AttachedPicture) { throw new System.InvalidCastException("Frame ID must be equal to copy the data within it."); } 00045 AttachedPicture i = AttachedPicture.Parse(other); 00046 this.Description = i.Description; 00047 this.Encoding = i.Encoding; 00048 this.ImageData = i.ImageData; 00049 this.MimeType = i.MimeType; 00050 this.Type = i.Type; 00051 this.Value = i.Value; 00052 } 00053 00054 public AttachedPicture(TextFrame other) 00055 : base(other) 00056 { 00057 if (other.ID != ID3.Frame.Keys.AttachedPicture) { throw new System.InvalidCastException("Frame ID must be equal to copy the data within it."); } 00058 this.ImageData = null; 00059 this.MimeType = string.Empty; 00060 this.Type = Picture.Other; 00061 } 00062 00063 public AttachedPicture(AttachedPicture other) 00064 : base(other) 00065 { 00066 this.MimeType = other.MimeType; 00067 this.Type = other.Type; 00068 this.ImageData = other.ImageData; 00069 } 00070 00071 private AttachedPicture(byte enc, string mime, byte pic, string desc, byte[] img) 00072 : base(ID3.Frame.Keys.AttachedPicture) 00073 { 00074 this.Initialize(enc, desc, mime, (Picture)pic, img); 00075 } 00076 00077 private void Initialize(System.Drawing.Image img, Picture type) 00078 { 00079 this.Initialize(0x00, string.Empty, string.Empty); 00080 this.SetImage(img, type); 00081 } 00082 00083 private void Initialize(byte enc, string desc, string mtype, Picture ptype, byte[] idata) 00084 { 00085 this.Initialize(enc, desc, string.Empty); 00086 this.MimeType = mtype; 00087 this.Type = ptype; 00088 this.ImageData = idata; 00089 this.GenerateTag(); 00090 } 00091 00092 // TODO: need to set the underlying member values for each "Frame" type 00093 00099 public override byte[] GenerateTag() 00100 { 00101 /* <Header for 'Attached picture', ID: "APIC"> 00102 Text encoding $xx (1 byte) 00103 MIME type <text string> (upto 0x00) 00104 Picture type $xx (1 byte) 00105 Description <text string according to encoding> (upto 0x00) 00106 Picture data <binary data> 00107 */ 00108 List<byte> ret = new List<byte>(); 00109 System.Text.Encoding enc = ID3.Helper.GetEncoding(this.Encoding); 00110 ret.Add(this.Encoding); 00111 byte[] mt = ID3.Helper.ISO.GetBytes(this.MimeType); 00112 if (mt != null && mt.Length > 0) { ret.AddRange(mt); } 00113 ret.Add(0x00); 00114 ret.Add((byte)this.Type); 00115 mt = enc.GetBytes(this.Description); 00116 if (mt != null && mt.Length > 0) { ret.AddRange(mt); } 00117 ret.Add(0x00); 00118 if (this.ImageData != null) { 00119 byte[] idata = this.ImageData; 00120 if (this.Format.IsCompressed) { 00121 idata = Frame.Compress(idata); 00122 } 00123 if (this.Format.IsEncrypted) { 00124 idata = Frame.Encrypt(idata, this.Format.Encryption); 00125 } 00126 if (this.Format.IsUnsynchronised) { 00127 idata = Frame.SyncData(idata); 00128 this.Format.DataLengthInicator = this.ImageData.Length; 00129 } 00130 ret.AddRange(idata); 00131 } 00132 this.Data = ret.ToArray(); 00133 return this.FullFrame; 00134 } 00135 00140 public void SetImage(System.Drawing.Image img, Picture type) 00141 { 00142 if (img == null) { throw new System.ArgumentNullException("img"); } 00143 this.MimeType = Sylloge.Data.Imaging.GetMimeType(img); 00144 this.ImageData = Sylloge.Data.Imaging.ToByteArray(img, this.MimeType); 00145 this.Type = type; 00146 this.GenerateTag(); 00147 } 00148 00153 public System.Drawing.Image ToImage() 00154 { 00155 if (this.ImageData == null) { return null; } 00156 System.IO.MemoryStream st = new System.IO.MemoryStream(this.ImageData); 00157 System.Drawing.Image ret = null; 00158 try { 00159 ret = System.Drawing.Image.FromStream(st); 00160 } catch (Exception) { 00161 // TODO: this should only happen on an improperly parsed 00162 // image data (i.e. missed a bit flag or didn't uncompress) 00163 ret = null; 00164 } 00165 return ret; 00166 } 00167 00172 public override string ToString() 00173 { 00174 return ((string.IsNullOrEmpty(this.Description)) ? this.MimeType : this.Description); 00175 } 00176 00177 public static ID3.Frames.AttachedPicture Parse(ID3.Frame frame) 00178 { 00179 if (frame.ID != ID3.Frame.Keys.AttachedPicture) { throw new System.InvalidCastException("Frame ID must be equal to copy the data within it."); } 00180 AttachedPicture ret = new AttachedPicture();// (Image)frame; 00181 ret.Data = frame.Data; 00182 ret.Format = frame.Format; 00183 ret.Status = frame.Status; 00184 ret.Value = string.Empty; 00185 /* <Header for 'Attached picture', ID: "APIC"> 00186 Text encoding $xx (1 byte) 00187 MIME type <text string> (upto 0x00) 00188 Picture type $xx (1 byte) 00189 Description <text string according to encoding> (upto 0x00, the terminating null char) 00190 Picture data <binary data> 00191 TE ( MIME TYPE ) PT 00192 <header> 00 69 6D 61 67 65 2F 4A 50 47 00 03 00 <image>*/ 00193 List<byte> bdata = new List<byte>(ret.Data); 00194 ret.Encoding = bdata[0]; bdata.RemoveAt(0); 00195 System.Text.Encoding enc = ID3.Helper.GetEncoding(ret.Encoding); 00196 ret.MimeType = ID3.Helper.ISO.GetString(bdata.ToArray()); 00197 int idx = 0; 00198 for (; idx < ret.MimeType.Length; idx++) { 00199 if (ret.MimeType[idx] == '\0') { break; } 00200 } 00201 ret.MimeType = ret.MimeType.Substring(0, idx); 00202 bdata.RemoveRange(0, ret.MimeType.Length + 1); 00203 byte ptype = bdata[0]; bdata.RemoveAt(0); // get picture type 00204 if (!ID3.Helper.CheckPictureType(ptype)) { ptype = Frame.EOL; } // eol for pic type is 'Other' 00205 ret.Type = (Picture)ptype; 00206 ret.Description = string.Empty; 00207 if (bdata[0] != Frame.EOL) { 00208 ret.Description = enc.GetString(bdata.ToArray()); 00209 for (idx = 0; idx < ret.Description.Length; idx++) { 00210 if (ret.Description[idx] == '\0') { break; } 00211 } 00212 ret.Description = ret.Description.Substring(0, idx); 00213 int len = enc.GetByteCount(ret.Description); 00214 if ((len + 1) > bdata.Count) { 00215 bdata.Clear(); 00216 } else { 00217 bdata.RemoveRange(0, len + 1); 00218 } 00219 if (enc.GetByteCount("A") > 1) { 00220 // for multi-byte encodings 00221 bdata.RemoveAt(0); 00222 } 00223 } else { 00224 bdata.RemoveAt(0); 00225 } 00226 // get the image byte data 00227 if (ret.Format.HasData) { 00228 byte[] d = null; 00229 if (ret.Format.IsUnsynchronised) { 00230 d = Frame.UnsyncData(bdata.ToArray(), ret.Format.DataLengthInicator); 00231 } 00232 if (ret.Format.IsEncrypted) { 00233 d = Frame.Decrypt(d, ret.Format.Encryption); 00234 } 00235 if (ret.Format.IsCompressed) { 00236 d = Frame.Decompress(d); 00237 } 00238 ret.ImageData = d; 00239 } else { 00240 ret.ImageData = bdata.ToArray(); 00241 } 00242 // retun the ID3 image 00243 return ret; 00244 } 00245 00251 public static ID3.Frames.AttachedPicture Parse(byte[] data) 00252 { 00253 /* <Header for 'Attached picture', ID: "APIC"> 00254 Text encoding $xx (1 byte) 00255 MIME type <text string> (upto 0x00) 00256 Picture type $xx (1 byte) 00257 Description <text string according to encoding> (upto 0x00, the terminating null char) 00258 Picture data <binary data> 00259 TE ( MIME TYPE ) PT 00260 <header> 00 69 6D 61 67 65 2F 4A 50 47 00 03 00 <image>*/ 00261 List<byte> bdata = new List<byte>(data); 00262 byte benc = bdata[0]; bdata.RemoveAt(0); 00263 System.Text.Encoding enc = ID3.Helper.GetEncoding(benc); 00264 string mtype = ID3.Helper.ISO.GetString(bdata.ToArray()); 00265 int idx = 0; 00266 for (; idx < mtype.Length; idx++) { 00267 if (mtype[idx] == '\0') { break; } 00268 } 00269 mtype = mtype.Substring(0, idx); 00270 bdata.RemoveRange(0, mtype.Length + 1); 00271 byte ptype = bdata[0]; bdata.RemoveAt(0); // get picture type 00272 if (!ID3.Helper.CheckPictureType(ptype)) { ptype = Frame.EOL; } // eol for pic type is 'Other' 00273 string desc = string.Empty; 00274 if (bdata[0] != Frame.EOL) { 00275 desc = enc.GetString(bdata.ToArray()); 00276 for (idx = 0; idx < desc.Length; idx++) { 00277 if (desc[idx] == '\0') { break; } 00278 } 00279 desc = desc.Substring(0, idx); 00280 int len = enc.GetByteCount(desc); 00281 if ((len + 1) > bdata.Count) { 00282 bdata.Clear(); 00283 } else { 00284 bdata.RemoveRange(0, len + 1); 00285 } 00286 } 00287 bdata.RemoveAt(0); 00288 // get the image byte data 00289 byte[] idata = bdata.ToArray(); 00290 // retun the ID3 image 00291 return (new ID3.Frames.AttachedPicture(benc, mtype, ptype, desc, idata)); 00292 } 00293 00300 public static bool TryParse(byte[] data, out ID3.Frames.AttachedPicture img) 00301 { 00302 try { 00303 img = AttachedPicture.Parse(data); 00304 } catch (Exception) { 00305 img = null; 00306 } 00307 return false; 00308 } 00309 } 00310 }