private void AddIptcProperties(JpegHeader header) { IptcFile iptc = header.GetIptc(); if (iptc == null) { return; } foreach (DataSet data in iptc.Sets) { switch (data.ID) { case DataSetID.ContentLocationName: AddProperty(Beagle.Property.New("iptc:location", data.XmpObject)); break; case DataSetID.CaptionAbstract: AddProperty(Beagle.Property.New("iptc:caption", data.XmpObject)); break; case DataSetID.Keywords: AddProperty(Beagle.Property.NewKeyword("iptc:keyword", data.XmpObject)); AddProperty(Beagle.Property.NewUnstored("image:tag", data.XmpObject)); break; default: // FIXME: Anything else to index ? //Log.Debug ("Ignoring {0} = [{1}]", data.ID, data.XmpObject); break; } } }
public static int Main(string [] args) { JpegHeader data = new JpegHeader(args [0]); byte [] value = data.GetRawXmp(); if (value != null) { string xml = System.Text.Encoding.UTF8.GetString(value, 29, value.Length - 29); //System.Console.WriteLine (xml); } value = data.GetRaw("ICC_PROFILE"); if (value != null) { System.IO.FileStream stream = new System.IO.FileStream("profile.icc", System.IO.FileMode.Create); stream.Write(value, 12, value.Length - 12); stream.Close(); } value = data.GetRawExif(); //System.IO.Stream ostream = System.IO.File.Open ("/home/lewing/test.jpg", System.IO.FileMode.OpenOrCreate); //data.Save (ostream); //ostream.Position = 0; //data = new JpegHeader (ostream); return(0); }
private void AddXmpProperties(JpegHeader header) { XmpFile xmp = header.GetXmp(); if (xmp != null) { AddXmpProperties(xmp); } }
public void Select(SemWeb.StatementSink sink) { byte [] data = GetEmbeddedJpeg(); if (data != null) { System.IO.Stream stream = new System.IO.MemoryStream(data); JpegHeader header = new JpegHeader(stream); header.Select(sink); } }
// FIXME: This is not particularly efficient protected override void PullImageProperties() { JpegHeader header = new JpegHeader(Stream); AddJfifProperties(header); AddExifProperties(header); AddXmpProperties(header); AddIptcProperties(header); Finished(); // That's all folks... }
//public DecodedJpeg Decode() //{ // JPEGFrame frame = null; // int num2; // Func<double, double> func2 = null; // bool flag3; // int resetInterval = 0; // bool flag = false; // bool flag2 = false; // List<JpegHeader> metaHeaders = new List<JpegHeader>(); // goto Label_09C3; //Label_03AF: // num2 = 0; // while (num2 < frame.ComponentCount) // { // byte componentID = this.jpegReader.ReadByte(); // byte num4 = this.jpegReader.ReadByte(); // byte quantizationTableID = this.jpegReader.ReadByte(); // byte sampleHFactor = (byte)(num4 >> 4); // byte sampleVFactor = (byte)(num4 & 15); // frame.AddComponent(componentID, sampleHFactor, sampleVFactor, quantizationTableID); // num2++; // } //Label_0998: // if (flag) // { // flag = false; // } // else // { // try // { // this.marker = this.jpegReader.GetNextMarker(); // } // catch (EndOfStreamException) // { // return new DecodedJpeg(this.image, metaHeaders); // } // } //Label_09C3: // flag3 = true; // if (this.DecodeProgress.Abort) // { // return null; // } // switch (this.marker) // { // case 0xc0: // case 0xc2: // this.progressive = this.marker == 0xc2; // this.jpegFrames.Add(new JPEGFrame()); // frame = this.jpegFrames[this.jpegFrames.Count - 1]; // frame.ProgressUpdateMethod = new Action<long>(this.UpdateStreamProgress); // this.jpegReader.ReadShort(); // frame.setPrecision(this.jpegReader.ReadByte()); // frame.ScanLines = this.jpegReader.ReadShort(); // frame.SamplesPerLine = this.jpegReader.ReadShort(); // frame.ComponentCount = this.jpegReader.ReadByte(); // this.DecodeProgress.Height = frame.Height; // this.DecodeProgress.Width = frame.Width; // this.DecodeProgress.SizeReady = true; // if (this.DecodeProgressChanged == null) // { // goto Label_03AF; // } // this.DecodeProgressChanged(this, this.DecodeProgress); // if (!this.DecodeProgress.Abort) // { // goto Label_03AF; // } // return null; // case 0xc1: // case 0xc3: // case 0xc5: // case 0xc6: // case 0xc7: // case 0xc9: // case 0xca: // case 0xcb: // case 0xcd: // case 0xce: // case 0xcf: // throw new NotSupportedException("Unsupported codec type."); // case 0xc4: // { // int num8 = this.jpegReader.ReadShort() - 2; // int num9 = num8; // while (num9 > 0) // { // byte num10 = this.jpegReader.ReadByte(); // byte num11 = (byte)(num10 >> 4); // byte index = (byte)(num10 & 15); // short[] lengths = new short[0x10]; // for (num2 = 0; num2 < lengths.Length; num2++) // { // lengths[num2] = this.jpegReader.ReadByte(); // } // int num13 = 0; // for (num2 = 0; num2 < 0x10; num2++) // { // num13 += lengths[num2]; // } // num9 -= num13 + 0x11; // short[] values = new short[num13]; // for (num2 = 0; num2 < values.Length; num2++) // { // values[num2] = this.jpegReader.ReadByte(); // } // if (num11 == HuffmanTable.JPEG_DC_TABLE) // { // this.dcTables[index] = new JpegHuffmanTable(lengths, values); // } // else if (num11 == HuffmanTable.JPEG_AC_TABLE) // { // this.acTables[index] = new JpegHuffmanTable(lengths, values); // } // } // goto Label_0998; // } // case 200: // case 0xcc: // case 0xd0: // case 0xd1: // case 210: // case 0xd3: // case 0xd4: // case 0xd5: // case 0xd6: // case 0xd7: // case 0xd8: // case 0xde: // case 0xdf: // case 240: // case 0xf1: // case 0xf2: // case 0xf3: // case 0xf4: // case 0xf5: // case 0xf6: // case 0xf7: // case 0xf8: // case 0xf9: // case 250: // case 0xfb: // case 0xfc: // case 0xfd: // goto Label_0998; // case 0xd9: // { // ColorModel model; // ColorModel model4; // if (this.jpegFrames.Count == 0) // { // throw new NotSupportedException("No JPEG frames could be located."); // } // if (this.jpegFrames.Count != 1) // { // throw new NotSupportedException("Unsupported Codec Type: Hierarchial JPEG"); // } // byte[][,] raster = Image.CreateRaster(frame.Width, frame.Height, frame.ComponentCount); // IList<JpegComponent> components = frame.Scan.Components; // int stepsTotal = components.Count * 3; // int num27 = 0; // for (num2 = 0; num2 < components.Count; num2++) // { // JpegComponent component = components[num2]; // component.QuantizationTable = this.qTables[component.quant_id].Table; // component.quantizeData(); // this.UpdateProgress(++num27, stepsTotal); // component.idctData(); // this.UpdateProgress(++num27, stepsTotal); // component.writeDataScaled(raster, num2, this.BlockUpsamplingMode); // this.UpdateProgress(++num27, stepsTotal); // component = null; // GC.Collect(); // } // if (frame.ComponentCount == 1) // { // model4 = new ColorModel(); // ColorModel model2 = model4; // model2.colorspace = ColorSpace.Gray; // model2.Opaque = true; // model = model2; // this.image = new Image(model, raster); // } // else // { // if (frame.ComponentCount != 3) // { // throw new NotSupportedException("Unsupported Color Mode: 4 Component Color Mode found."); // } // model4 = new ColorModel(); // ColorModel model3 = model4; // model3.colorspace = ColorSpace.YCbCr; // model3.Opaque = true; // model = model3; // this.image = new Image(model, raster); // } // if (func2 == null) // { // func2 = delegate(double x) // { // return (this.Units == UnitType.Inches) ? x : (x / 2.54); // }; // } // Func<double, double> func = func2; // this.image.DensityX = func((double)this.XDensity); // this.image.DensityY = func((double)this.YDensity); // this.height = frame.Height; // this.width = frame.Width; // goto Label_0998; // } // case 0xda: // { // Debug.WriteLine("Start of Scan (SOS)"); // ushort num17 = this.jpegReader.ReadShort(); // byte numberOfComponents = this.jpegReader.ReadByte(); // byte[] componentSelector = new byte[numberOfComponents]; // num2 = 0; // while (num2 < numberOfComponents) // { // byte num19 = this.jpegReader.ReadByte(); // byte num20 = this.jpegReader.ReadByte(); // int num21 = (num20 >> 4) & 15; // int num22 = num20 & 15; // frame.setHuffmanTables(num19, this.acTables[(byte)num22], this.dcTables[(byte)num21]); // componentSelector[num2] = num19; // num2++; // } // byte startSpectralSelection = this.jpegReader.ReadByte(); // byte endSpectralSelection = this.jpegReader.ReadByte(); // byte successiveApproximation = this.jpegReader.ReadByte(); // if (!this.progressive) // { // frame.DecodeScanBaseline(numberOfComponents, componentSelector, resetInterval, this.jpegReader, ref this.marker); // flag = true; // } // if (this.progressive) // { // frame.DecodeScanProgressive(successiveApproximation, startSpectralSelection, endSpectralSelection, numberOfComponents, componentSelector, resetInterval, this.jpegReader, ref this.marker); // flag = true; // } // goto Label_0998; // } // case 0xdb: // { // short num14 = (short)(this.jpegReader.ReadShort() - 2); // for (int i = 0; i < (num14 / 0x41); i++) // { // byte num16 = this.jpegReader.ReadByte(); // int[] table = new int[0x40]; // if (((byte)(num16 >> 4)) == 0) // { // for (num2 = 0; num2 < 0x40; num2++) // { // table[num2] = this.jpegReader.ReadByte(); // } // } // else if (((byte)(num16 >> 4)) == 1) // { // for (num2 = 0; num2 < 0x40; num2++) // { // table[num2] = this.jpegReader.ReadShort(); // } // } // this.qTables[num16 & 15] = new JpegQuantizationTable(table); // } // goto Label_0998; // } // case 220: // frame.ScanLines = this.jpegReader.ReadShort(); // goto Label_0998; // case 0xdd: // this.jpegReader.BaseStream.Seek(2L, SeekOrigin.Current); // resetInterval = this.jpegReader.ReadShort(); // goto Label_0998; // case 0xe0: // case 0xe1: // case 0xe2: // case 0xe3: // case 0xe4: // case 0xe5: // case 230: // case 0xe7: // case 0xe8: // case 0xe9: // case 0xea: // case 0xeb: // case 0xec: // case 0xed: // case 0xee: // case 0xef: // case 0xfe: // { // JpegHeader item = this.ExtractHeader(); // if ((item.Marker == 0xe1) && (item.Data.Length >= 6)) // { // byte[] data = item.Data; // if (((((data[0] == 0x45) && (data[1] == 120)) && ((data[2] == 0x69) && (data[3] == 0x66))) && (data[4] == 0)) && (data[5] == 0)) // { // } // } // if (((item.Data.Length >= 5) && (item.Marker == 0xee)) && (Encoding.UTF8.GetString(item.Data, 0, 5) == "Adobe")) // { // } // metaHeaders.Add(item); // if ((!flag2 && (this.marker == 0xe0)) && this.TryParseJFIF(item.Data)) // { // item.IsJFIF = true; // this.marker = this.jpegReader.GetNextMarker(); // if (this.marker == 0xe0) // { // item = this.ExtractHeader(); // metaHeaders.Add(item); // } // else // { // flag = true; // } // } // goto Label_0998; // } // } // goto Label_0998; //} private JpegHeader ExtractHeader() { int count = this.jpegReader.ReadShort() - 2; byte[] buffer = new byte[count]; this.jpegReader.Read(buffer, 0, count); JpegHeader header2 = new JpegHeader(); header2.Marker = this.marker; header2.Data = buffer; return(header2); }
public override Stream PixbufStream () { if (header != null) return Open (); Stream s = Open (); if (s.CanSeek) { header = new JpegHeader (s, true); s.Position = 0; } else Console.WriteLine ("{0} can not seek :(", s); return s; }
public void Save() { string in_path = CreateFile(); string out_path = ImageFile.TempPath("output.jpg"); JpegHeader source; JpegHeader dest; using (Stream orig = File.OpenRead(in_path)) { source = new JpegHeader(orig); using (Stream output = File.OpenWrite(out_path)) { source.Save(output); } using (Stream result = File.OpenRead(out_path)) { dest = new JpegHeader(result); Assert.AreEqual(source.Markers.Count, dest.Markers.Count); Assert.AreEqual(source.GuessQuality(), dest.GuessQuality()); Assert.AreEqual(orig.Length, result.Length); for (int i = 0; i < source.Markers.Count; i++) { Marker d = (Marker)dest.Markers [i]; Marker s = (Marker)source.Markers [i]; Assert.AreEqual(d.Type, s.Type); Assert.AreEqual(d.GetName(), s.GetName()); if (d.Data != null) { Assert.AreEqual(d.Data.Length, s.Data.Length); for (int j = 0; j < d.Data.Length; j++) { Assert.AreEqual(d.Data [j], s.Data [j]); } } else { Assert.AreEqual(d.Data, s.Data); } } } } File.Delete(in_path); File.Delete(out_path); }
private JpegHeader ExtractHeader() { #region Extract the header int length = jpegReader.ReadShort() - 2; byte[] data = new byte[length]; jpegReader.Read(data, 0, length); #endregion JpegHeader header = new JpegHeader() { Marker = marker, Data = data }; return(header); }
private void SaveMetaData(System.IO.Stream input, System.IO.Stream output) { JpegHeader header = new JpegHeader(input); UpdateMeta(); // Console.WriteLine ("updated metadata"); header.SetExif(this.ExifData); // Console.WriteLine ("set exif"); if (xmp != null) { header.SetXmp(xmp); } // Console.WriteLine ("set xmp"); header.Save(output); // Console.WriteLine ("saved"); }
public void Load() { string path = CreateFile(); using (Stream stream = File.OpenRead(path)) { JpegHeader jhead = new JpegHeader(stream); Assert.AreEqual(((Marker)jhead.Markers [0]).Type, JpegMarker.Soi); Assert.AreEqual(((Marker)jhead.Markers [1]).GetName(), "JFIF"); Assert.AreEqual(((Marker)jhead.Markers [1]).Type, JpegMarker.App0); Assert.AreEqual(((Marker)jhead.Markers [2]).GetName(), "Exif"); Assert.AreEqual(((Marker)jhead.Markers [2]).Type, JpegMarker.App1); // NOTE the currently we don't store the Eoi as the last marker Assert.AreEqual(((Marker)jhead.Markers [jhead.Markers.Count - 1]).Type, JpegMarker.Sos); // NOTE this is kind of sill but it might help Assert.IsTrue(Math.Abs(jhead.GuessQuality() - quality) <= 1); Assert.IsNotNull(jhead.GetExifHeader()); } File.Delete(path); }
public void Select (SemWeb.StatementSink sink) { byte [] data = GetEmbeddedJpeg (); if (data != null) { System.IO.Stream stream = new System.IO.MemoryStream (data); JpegHeader header = new JpegHeader (stream); header.Select (sink); } }
public static int Main (string [] args) { JpegHeader data = new JpegHeader (args [0]); byte [] value = data.GetRawXmp (); if (value != null) { string xml = System.Text.Encoding.UTF8.GetString (value, 29, value.Length - 29); //System.Console.WriteLine (xml); } value = data.GetRaw ("ICC_PROFILE"); if (value != null) { System.IO.FileStream stream = new System.IO.FileStream ("profile.icc", System.IO.FileMode.Create); stream.Write (value, 12, value.Length - 12); stream.Close (); } value = data.GetRawExif (); //System.IO.Stream ostream = System.IO.File.Open ("/home/lewing/test.jpg", System.IO.FileMode.OpenOrCreate); //data.Save (ostream); //ostream.Position = 0; //data = new JpegHeader (ostream); return 0; }
private JpegHeader ExtractHeader() { #region Extract the header int length = jpegReader.ReadShort() - 2; byte[] data = new byte[length]; jpegReader.Read(data, 0, length); #endregion JpegHeader header = new JpegHeader() { Marker = marker, Data = data }; return header; }
public void Load () { string path = CreateFile (); using (Stream stream = File.OpenRead (path)) { JpegHeader jhead = new JpegHeader (stream); Assert.AreEqual (((Marker)jhead.Markers [0]).Type, JpegMarker.Soi); Assert.AreEqual (((Marker)jhead.Markers [1]).GetName (), "JFIF"); Assert.AreEqual (((Marker)jhead.Markers [1]).Type, JpegMarker.App0); Assert.AreEqual (((Marker)jhead.Markers [2]).GetName (), "Exif"); Assert.AreEqual (((Marker)jhead.Markers [2]).Type, JpegMarker.App1); // NOTE the currently we don't store the Eoi as the last marker Assert.AreEqual (((Marker)jhead.Markers [jhead.Markers.Count -1]).Type, JpegMarker.Sos); // NOTE this is kind of sill but it might help Assert.IsTrue (Math.Abs (jhead.GuessQuality () - quality) <= 1); Assert.IsNotNull (jhead.GetExifHeader ()); } File.Delete (path); }
public void Save () { string in_path = CreateFile (); string out_path = ImageFile.TempPath ("output.jpg"); JpegHeader source; JpegHeader dest; using (Stream orig = File.OpenRead (in_path)) { source = new JpegHeader (orig); using (Stream output = File.OpenWrite (out_path)) { source.Save (output); } using (Stream result = File.OpenRead (out_path)) { dest = new JpegHeader (result); Assert.AreEqual (source.Markers.Count, dest.Markers.Count); Assert.AreEqual (source.GuessQuality (), dest.GuessQuality ()); Assert.AreEqual (orig.Length, result.Length); for (int i = 0; i < source.Markers.Count; i++) { Marker d = (Marker) dest.Markers [i]; Marker s = (Marker) source.Markers [i]; Assert.AreEqual (d.Type, s.Type); Assert.AreEqual (d.GetName (), s.GetName ()); if (d.Data != null) { Assert.AreEqual (d.Data.Length, s.Data.Length); for (int j = 0; j < d.Data.Length; j++) { Assert.AreEqual (d.Data [j], s.Data [j]); } } else { Assert.AreEqual (d.Data, s.Data); } } } } File.Delete (in_path); File.Delete (out_path); }
public DecodedJpeg Decode() { JPEGFrame jPEGFrame = null; int resetInterval = 0; bool flag = false; bool flag2 = false; List <JpegHeader> list = new List <JpegHeader>(); while (true) { if (DecodeProgress.Abort) { return(null); } switch (marker) { case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 237: case 238: case 239: case 254: { JpegHeader jpegHeader = ExtractHeader(); if (jpegHeader.Marker == 225 && jpegHeader.Data.Length >= 6) { byte[] data = jpegHeader.Data; if (data[0] == 69 && data[1] == 120 && data[2] == 105 && data[3] == 102 && data[4] == 0) { _ = data[5]; } } if (jpegHeader.Data.Length >= 5 && jpegHeader.Marker == 238) { _ = (Encoding.UTF8.GetString(jpegHeader.Data, 0, 5) == "Adobe"); } list.Add(jpegHeader); if (flag2 || marker != 224) { break; } flag2 = TryParseJFIF(jpegHeader.Data); if (flag2) { jpegHeader.IsJFIF = true; marker = jpegReader.GetNextMarker(); if (marker == 224) { jpegHeader = ExtractHeader(); list.Add(jpegHeader); } else { flag = true; } } break; } case 192: case 194: { progressive = (marker == 194); jpegFrames.Add(new JPEGFrame()); jPEGFrame = jpegFrames[jpegFrames.Count - 1]; jPEGFrame.ProgressUpdateMethod = UpdateStreamProgress; jpegReader.ReadShort(); jPEGFrame.setPrecision(jpegReader.ReadByte()); jPEGFrame.ScanLines = jpegReader.ReadShort(); jPEGFrame.SamplesPerLine = jpegReader.ReadShort(); jPEGFrame.ComponentCount = jpegReader.ReadByte(); DecodeProgress.Height = jPEGFrame.Height; DecodeProgress.Width = jPEGFrame.Width; DecodeProgress.SizeReady = true; if (this.DecodeProgressChanged != null) { this.DecodeProgressChanged(this, DecodeProgress); if (DecodeProgress.Abort) { return(null); } } for (int m = 0; m < jPEGFrame.ComponentCount; m++) { byte componentID = jpegReader.ReadByte(); byte num5 = jpegReader.ReadByte(); byte quantizationTableID = jpegReader.ReadByte(); byte sampleHFactor = (byte)(num5 >> 4); byte sampleVFactor = (byte)(num5 & 0xF); jPEGFrame.AddComponent(componentID, sampleHFactor, sampleVFactor, quantizationTableID); } break; } case 196: { int num2 = jpegReader.ReadShort() - 2; while (num2 > 0) { byte num3 = jpegReader.ReadByte(); byte b = (byte)(num3 >> 4); byte b2 = (byte)(num3 & 0xF); short[] array = new short[16]; for (int j = 0; j < array.Length; j++) { array[j] = jpegReader.ReadByte(); } int num4 = 0; for (int k = 0; k < 16; k++) { num4 += array[k]; } num2 -= num4 + 17; short[] array2 = new short[num4]; for (int l = 0; l < array2.Length; l++) { array2[l] = jpegReader.ReadByte(); } if (b == HuffmanTable.JPEG_DC_TABLE) { dcTables[b2] = new JpegHuffmanTable(array, array2); } else if (b == HuffmanTable.JPEG_AC_TABLE) { acTables[b2] = new JpegHuffmanTable(array, array2); } } break; } case 219: { short num9 = (short)(jpegReader.ReadShort() - 2); for (int num10 = 0; num10 < num9 / 65; num10++) { byte b5 = jpegReader.ReadByte(); int[] array4 = new int[64]; if ((byte)(b5 >> 4) == 0) { for (int num11 = 0; num11 < 64; num11++) { array4[num11] = jpegReader.ReadByte(); } } else if ((byte)(b5 >> 4) == 1) { for (int num12 = 0; num12 < 64; num12++) { array4[num12] = jpegReader.ReadShort(); } } qTables[b5 & 0xF] = new JpegQuantizationTable(array4); } break; } case 218: { jpegReader.ReadShort(); byte b3 = jpegReader.ReadByte(); byte[] array3 = new byte[b3]; for (int n = 0; n < b3; n++) { byte b4 = jpegReader.ReadByte(); byte num6 = jpegReader.ReadByte(); int num7 = (num6 >> 4) & 0xF; int num8 = num6 & 0xF; jPEGFrame.setHuffmanTables(b4, acTables[(byte)num8], dcTables[(byte)num7]); array3[n] = b4; } byte startSpectralSelection = jpegReader.ReadByte(); byte endSpectralSelection = jpegReader.ReadByte(); byte successiveApproximation = jpegReader.ReadByte(); if (!progressive) { jPEGFrame.DecodeScanBaseline(b3, array3, resetInterval, jpegReader, ref marker); flag = true; } if (progressive) { jPEGFrame.DecodeScanProgressive(successiveApproximation, startSpectralSelection, endSpectralSelection, b3, array3, resetInterval, jpegReader, ref marker); flag = true; } break; } case 221: jpegReader.BaseStream.Seek(2L, SeekOrigin.Current); resetInterval = jpegReader.ReadShort(); break; case 220: jPEGFrame.ScanLines = jpegReader.ReadShort(); break; case 217: { if (jpegFrames.Count == 0) { throw new NotSupportedException("No JPEG frames could be located."); } if (jpegFrames.Count > 1) { jPEGFrame = jpegFrames.OrderByDescending((JPEGFrame f) => f.Width * f.Height).FirstOrDefault(); } byte[][,] raster = Image.CreateRaster(jPEGFrame.Width, jPEGFrame.Height, jPEGFrame.ComponentCount); IList <JpegComponent> components = jPEGFrame.Scan.Components; int stepsTotal = components.Count * 3; int num = 0; for (int i = 0; i < components.Count; i++) { JpegComponent jpegComponent = components[i]; jpegComponent.QuantizationTable = qTables[jpegComponent.quant_id].Table; jpegComponent.quantizeData(); UpdateProgress(++num, stepsTotal); jpegComponent.idctData(); UpdateProgress(++num, stepsTotal); jpegComponent.writeDataScaled(raster, i, BlockUpsamplingMode); UpdateProgress(++num, stepsTotal); jpegComponent = null; GC.Collect(); } ColorModel colorModel; if (jPEGFrame.ComponentCount == 1) { colorModel = default(ColorModel); colorModel.colorspace = ColorSpace.Gray; colorModel.Opaque = true; ColorModel cm = colorModel; image = new Image(cm, raster); } else { if (jPEGFrame.ComponentCount != 3) { throw new NotSupportedException("Unsupported Color Mode: 4 Component Color Mode found."); } colorModel = default(ColorModel); colorModel.colorspace = ColorSpace.YCbCr; colorModel.Opaque = true; ColorModel cm2 = colorModel; image = new Image(cm2, raster); } Func <double, double> func = (double x) => (Units != UnitType.Inches) ? (x / 2.54) : x; image.DensityX = func((int)XDensity); image.DensityY = func((int)YDensity); break; } case 193: case 195: case 197: case 198: case 199: case 201: case 202: case 203: case 205: case 206: case 207: throw new NotSupportedException("Unsupported codec type."); } if (flag) { flag = false; } else { try { marker = jpegReader.GetNextMarker(); } catch (EndOfStreamException) { break; } } } return(new DecodedJpeg(image, list)); }
private void AddExifProperties(JpegHeader header) { Tiff.Header ifd = header.GetExifHeader(); if (ifd == null) { return; } //ifd.Dump ("foo"); // Uncomment to debug string str; Tiff.DirectoryEntry entry; // Add IFD 0 properies str = GetExifString(ifd.Directory, Tiff.TagId.Model); AddProperty(Beagle.Property.New("exif:Model", str)); str = GetExifString(ifd.Directory, Tiff.TagId.ImageDescription); AddProperty(Beagle.Property.New("exif:ImageDescription", str)); try { entry = ifd.Directory.Lookup(Tiff.TagId.DateTime); if (entry != null) { // Assume datetime stored in the images are local times AddProperty(Beagle.Property.NewDate("exif:DateTime", entry.ValueAsDate.ToUniversalTime())); } } catch (FormatException) { Logger.Log.Debug("EXIF DateTime '{0}' is invalid.", GetExifString(ifd.Directory, Tiff.TagId.DateTime)); } catch (ArgumentOutOfRangeException) { Logger.Log.Debug("EXIF DateTime '{0}' is invalid.", GetExifString(ifd.Directory, Tiff.TagId.DateTime)); } str = GetExifString(ifd.Directory, Tiff.TagId.Copyright); AddProperty(Beagle.Property.New("dc:rights", str)); // Add IFD 1 properties Tiff.SubdirectoryEntry subdir = (Tiff.SubdirectoryEntry)ifd.Directory.Lookup(Tiff.TagId.ExifIfdPointer); if (subdir == null) { return; } Tiff.ImageDirectory exif = subdir.Directory [0]; if (exif == null) { return; } entry = exif.Lookup(Tiff.TagId.UserComment); if (entry != null) { AddProperty(Beagle.Property.New("exif:UserComment", entry.UserCommentValue)); } uint val = 0; entry = exif.Lookup(Tiff.TagId.PixelXDimension); if (entry != null) { val = entry.ValueAsLong [0]; } if (val > 0) { Width = (int)val; AddProperty(Beagle.Property.NewUnsearched("exif:PixelXDimension", val)); } val = 0; entry = exif.Lookup(Tiff.TagId.PixelYDimension); if (entry != null) { val = entry.ValueAsLong [0]; } if (val > 0) { Height = (int)val; AddProperty(Beagle.Property.NewUnsearched("exif:PixelYDimension", val)); } str = GetExifString(exif, Tiff.TagId.ISOSpeedRatings); AddProperty(Beagle.Property.NewUnsearched("exif:ISOSpeedRatings", str)); str = GetExifString(exif, Tiff.TagId.ShutterSpeedValue); AddProperty(Beagle.Property.NewUnsearched("exif:ShutterSpeedValue", str)); str = GetExifString(exif, Tiff.TagId.ExposureTime); if (!String.IsNullOrEmpty(str)) { AddProperty(Beagle.Property.NewUnsearched("exif:ExposureTime", str + " sec.")); } double rational_val; rational_val = GetExifRational(exif, Tiff.TagId.FNumber); if (rational_val > 0) { AddProperty(Beagle.Property.NewUnsearched("exif:FNumber", String.Format("f/{0}", rational_val))); } rational_val = GetExifRational(exif, Tiff.TagId.ApertureValue); if (rational_val > 0) { AddProperty(Beagle.Property.NewUnsearched("exif:ApertureValue", rational_val)); } rational_val = GetExifRational(exif, Tiff.TagId.FocalLength); if (rational_val > 0) { AddProperty(Beagle.Property.NewUnsearched("exif:FocalLength", String.Format("{0} mm", rational_val))); } entry = exif.Lookup(Tiff.TagId.Flash); if (entry != null) { ushort flash = entry.ShortValue [0]; AddProperty(Beagle.Property.NewUnsearched("exif:Flash", GetFlashString(flash))); } }
public IList <JpegHeader> ExtractHeaders() { // Extracts only the header (EXIF/XMP) data from the JPEG. This // method is useful if the JPEG is to be manipulated in any // way other than resizing (such as cropping), so that the metadata // can be easily re-added to the outputted JPEG. The separate call // is useful as loading the entire file just to pull the headers // is a very time consuming process bool haveMarker = false; bool foundJFIF = false; var headers = new List <JpegHeader>(); // Loop through until there are no more markers to read in, at // that point the headers have been fully extracted while (true) { if (DecodeProgress.Abort) { return(null); } #region Switch over marker types switch (marker) { case JPEGMarker.APP0: // APP1 is used for EXIF data case JPEGMarker.APP1: // Seldomly, APP2 gets used for extended EXIF, too case JPEGMarker.APP2: case JPEGMarker.APP3: case JPEGMarker.APP4: case JPEGMarker.APP5: case JPEGMarker.APP6: case JPEGMarker.APP7: case JPEGMarker.APP8: case JPEGMarker.APP9: case JPEGMarker.APP10: case JPEGMarker.APP11: case JPEGMarker.APP12: case JPEGMarker.APP13: case JPEGMarker.APP14: case JPEGMarker.APP15: // COM: Comment case JPEGMarker.COM: // We only want to extract the headers so they can be round tripped // easily with the JPEG needs to be resized JpegHeader header = ExtractHeader(); #region Check explicitly for Exif Data if (header.Marker == JPEGMarker.APP1 && header.Data.Length >= 6) { byte[] d = header.Data; if (d[0] == 'E' && d[1] == 'x' && d[2] == 'i' && d[3] == 'f' && d[4] == 0 && d[5] == 0) { // Exif. Do something? } } #endregion #region Check for Adobe header if (header.Data.Length >= 5 && header.Marker == JPEGMarker.APP14) { string asText = UTF8Encoding.UTF8.GetString(header.Data, 0, 5); if (asText == "Adobe") { // ADOBE HEADER. Do anything? } } #endregion headers.Add(header); if (!foundJFIF && marker == JPEGMarker.APP0) { foundJFIF = TryParseJFIF(header.Data); if (foundJFIF) // Found JFIF... do JFIF extension follow? { header.IsJFIF = true; marker = jpegReader.GetNextMarker(); // Yes, they do. if (marker == JPEGMarker.APP0) { header = ExtractHeader(); headers.Add(header); } else // No. Delay processing this one. { haveMarker = true; } } } break; case JPEGMarker.SOF0: case JPEGMarker.SOF2: break; case JPEGMarker.DHT: break; case JPEGMarker.DQT: break; case JPEGMarker.SOS: break; case JPEGMarker.DRI: break; case JPEGMarker.DNL: break; case JPEGMarker.EOI: break; case JPEGMarker.SOF1: case JPEGMarker.SOF3: case JPEGMarker.SOF5: case JPEGMarker.SOF6: case JPEGMarker.SOF7: case JPEGMarker.SOF9: case JPEGMarker.SOF10: case JPEGMarker.SOF11: case JPEGMarker.SOF13: case JPEGMarker.SOF14: case JPEGMarker.SOF15: throw new NotSupportedException("Unsupported codec type."); default: break; // ignore } #endregion switch over markers if (haveMarker) { haveMarker = false; } else { try { marker = jpegReader.GetNextMarker(); } catch (System.IO.EndOfStreamException) { break; /* done reading the file */ } } } return(headers); }
public DecodedJpeg Decode() { // The frames in this jpeg are loaded into a list. There is // usually just one frame except in heirarchial progression where // there are multiple frames. JPEGFrame frame = null; // The restart interval defines how many MCU's we should have // between the 8-modulo restart marker. The restart markers allow // us to tell whether or not our decoding process is working // correctly, also if there is corruption in the image we can // recover with these restart intervals. (See RSTm DRI). int resetInterval = 0; bool haveMarker = false; bool foundJFIF = false; List <JpegHeader> headers = new List <JpegHeader>(); // Loop through until there are no more markers to read in, at // that point everything is loaded into the jpegFrames array and // can be processed. while (true) { #region Switch over marker types switch (marker) { case JPEGMarker.APP0: // APP1 is used for EXIF data case JPEGMarker.APP1: // Seldomly, APP2 gets used for extended EXIF, too case JPEGMarker.APP2: case JPEGMarker.APP3: case JPEGMarker.APP4: case JPEGMarker.APP5: case JPEGMarker.APP6: case JPEGMarker.APP7: case JPEGMarker.APP8: case JPEGMarker.APP9: case JPEGMarker.APP10: case JPEGMarker.APP11: case JPEGMarker.APP12: case JPEGMarker.APP13: case JPEGMarker.APP14: case JPEGMarker.APP15: // COM: Comment case JPEGMarker.COM: // Debug.WriteLine(string.Format("Extracting Header, Type={0:X}", marker)); JpegHeader header = ExtractHeader(); #region Check explicitly for Exif Data if (header.Marker == JPEGMarker.APP1 && header.Data.Length >= 6) { byte[] d = header.Data; if (d[0] == 'E' && d[1] == 'x' && d[2] == 'i' && d[3] == 'f' && d[4] == 0 && d[5] == 0) { // Exif. Do something? } } #endregion #region Check for Adobe header if (header.Data.Length >= 5 && header.Marker == JPEGMarker.APP14) { string asText = UTF8Encoding.UTF8.GetString(header.Data, 0, 5); if (asText == "Adobe") { // ADOBE HEADER. Do anything? } } #endregion headers.Add(header); if (!foundJFIF && marker == JPEGMarker.APP0) { foundJFIF = TryParseJFIF(header.Data); if (foundJFIF) // Found JFIF... do JFIF extension follow? { header.IsJFIF = true; marker = jpegReader.GetNextMarker(); // Yes, they do. if (marker == JPEGMarker.APP0) { header = ExtractHeader(); headers.Add(header); } else // No. Delay processing this one. { haveMarker = true; } } } break; case JPEGMarker.SOF0: case JPEGMarker.SOF2: // SOFn Start of Frame Marker, Baseline DCT - This is the start // of the frame header that defines certain variables that will // be carried out through the rest of the encoding. Multiple // frames are used in a hierarchical system, however most JPEG's // only contain a single frame. // Progressive or baseline? progressive = marker == JPEGMarker.SOF2; jpegFrames.Add(new JPEGFrame()); frame = (JPEGFrame)jpegFrames[jpegFrames.Count - 1]; frame.ProgressUpdateMethod = new Action <long>(UpdateStreamProgress); // Skip the frame length. jpegReader.ReadShort(); // Bits percision, either 8 or 12. frame.setPrecision(jpegReader.ReadByte()); // Scan lines (height) frame.ScanLines = jpegReader.ReadShort(); // Scan samples per line (width) frame.SamplesPerLine = jpegReader.ReadShort(); // Number of Color Components (channels). frame.ComponentCount = jpegReader.ReadByte(); DecodeProgress.Height = frame.Height; DecodeProgress.Width = frame.Width; DecodeProgress.SizeReady = true; if (DecodeProgressChanged != null) { DecodeProgressChanged(this, DecodeProgress); } // Add all of the necessary components to the frame. for (int i = 0; i < frame.ComponentCount; i++) { byte compId = jpegReader.ReadByte(); byte sampleFactors = jpegReader.ReadByte(); byte qTableId = jpegReader.ReadByte(); byte sampleHFactor = (byte)(sampleFactors >> 4); byte sampleVFactor = (byte)(sampleFactors & 0x0f); frame.AddComponent(compId, sampleHFactor, sampleVFactor, qTableId); } break; case JPEGMarker.DHT: // DHT non-SOF Marker - Huffman Table is required for decoding // the JPEG stream, when we receive a marker we load in first // the table length (16 bits), the table class (4 bits), table // identifier (4 bits), then we load in 16 bytes and each byte // represents the count of bytes to load in for each of the 16 // bytes. We load this into an array to use later and move on 4 // huffman tables can only be used in an image. int huffmanLength = (jpegReader.ReadShort() - 2); // Keep looping until we are out of length. int index = huffmanLength; // Multiple tables may be defined within a DHT marker. This // will keep reading until there are no tables left, most // of the time there are just one tables. while (index > 0) { // Read the identifier information and class // information about the Huffman table, then read the // 16 byte codelength in and read in the Huffman values // and put it into table info. byte huffmanInfo = jpegReader.ReadByte(); byte tableClass = (byte)(huffmanInfo >> 4); byte huffmanIndex = (byte)(huffmanInfo & 0x0f); short[] codeLength = new short[16]; for (int i = 0; i < codeLength.Length; i++) { codeLength[i] = jpegReader.ReadByte(); } int huffmanValueLen = 0; for (int i = 0; i < 16; i++) { huffmanValueLen += codeLength[i]; } index -= (huffmanValueLen + 17); short[] huffmanVal = new short[huffmanValueLen]; for (int i = 0; i < huffmanVal.Length; i++) { huffmanVal[i] = jpegReader.ReadByte(); } // Assign DC Huffman Table. if (tableClass == HuffmanTable.JPEG_DC_TABLE) { dcTables[(int)huffmanIndex] = new JpegHuffmanTable(codeLength, huffmanVal); } // Assign AC Huffman Table. else if (tableClass == HuffmanTable.JPEG_AC_TABLE) { acTables[(int)huffmanIndex] = new JpegHuffmanTable(codeLength, huffmanVal); } } break; case JPEGMarker.DQT: // DQT non-SOF Marker - This defines the quantization // coeffecients, this allows us to figure out the quality of // compression and unencode the data. The data is loaded and // then stored in to an array. short quantizationLength = (short)(jpegReader.ReadShort() - 2); for (int j = 0; j < quantizationLength / 65; j++) { byte quantSpecs = jpegReader.ReadByte(); int[] quantData = new int[64]; if ((byte)(quantSpecs >> 4) == 0) // Precision 8 bit. { for (int i = 0; i < 64; i++) { quantData[i] = jpegReader.ReadByte(); } } else if ((byte)(quantSpecs >> 4) == 1) // Precision 16 bit. { for (int i = 0; i < 64; i++) { quantData[i] = jpegReader.ReadShort(); } } qTables[(int)(quantSpecs & 0x0f)] = new JpegQuantizationTable(quantData); } break; case JPEGMarker.SOS: Debug.WriteLine("Start of Scan (SOS)"); // SOS non-SOF Marker - Start Of Scan Marker, this is where the // actual data is stored in a interlaced or non-interlaced with // from 1-4 components of color data, if three components most // likely a YCrCb model, this is a fairly complex process. // Read in the scan length. //ushort scanLen = jpegReader.ReadShort(); // Number of components in the scan. byte numberOfComponents = jpegReader.ReadByte(); byte[] componentSelector = new byte[numberOfComponents]; for (int i = 0; i < numberOfComponents; i++) { // Component ID, packed byte containing the Id for the // AC table and DC table. byte componentID = jpegReader.ReadByte(); byte tableInfo = jpegReader.ReadByte(); int DC = (tableInfo >> 4) & 0x0f; int AC = (tableInfo) & 0x0f; frame.setHuffmanTables(componentID, acTables[(byte)AC], dcTables[(byte)DC]); componentSelector[i] = componentID; } byte startSpectralSelection = jpegReader.ReadByte(); byte endSpectralSelection = jpegReader.ReadByte(); byte successiveApproximation = jpegReader.ReadByte(); #region Baseline JPEG Scan Decoding if (!progressive) { frame.DecodeScanBaseline(numberOfComponents, componentSelector, resetInterval, jpegReader, ref marker); haveMarker = true; // use resultant marker for the next switch(..) } #endregion #region Progressive JPEG Scan Decoding if (progressive) { frame.DecodeScanProgressive( successiveApproximation, startSpectralSelection, endSpectralSelection, numberOfComponents, componentSelector, resetInterval, jpegReader, ref marker); haveMarker = true; // use resultant marker for the next switch(..) } #endregion break; case JPEGMarker.DRI: jpegReader.BaseStream.Seek(2, System.IO.SeekOrigin.Current); resetInterval = jpegReader.ReadShort(); break; // Defines the number of lines. (Not usually present) case JPEGMarker.DNL: frame.ScanLines = jpegReader.ReadShort(); break; // End of Image. Finish the decode. case JPEGMarker.EOI: if (jpegFrames.Count == 0) { throw new NotSupportedException("No JPEG frames could be located."); } else if (jpegFrames.Count == 1) { // Only one frame, JPEG Non-Heirarchial Frame. byte[][,] raster = Image.CreateRaster(frame.Width, frame.Height, frame.ComponentCount); IList <JpegComponent> components = frame.Scan.Components; int totalSteps = components.Count * 3; // Three steps per loop int stepsFinished = 0; for (int i = 0; i < components.Count; i++) { JpegComponent comp = components[i]; comp.QuantizationTable = qTables[comp.quant_id].Table; // 1. Quantize comp.quantizeData(); UpdateProgress(++stepsFinished, totalSteps); // 2. Run iDCT (expensive) comp.idctData(); UpdateProgress(++stepsFinished, totalSteps); // 3. Scale the image and write the data to the raster. comp.writeDataScaled(raster, i, BlockUpsamplingMode); UpdateProgress(++stepsFinished, totalSteps); // Ensure garbage collection. comp = null; GC.Collect(); } // Grayscale Color Image (1 Component). if (frame.ComponentCount == 1) { ColorModel cm = new ColorModel() { ColorSpace = ColorSpace.Gray, Opaque = true }; image = new Image(cm, raster); } // YCbCr Color Image (3 Components). else if (frame.ComponentCount == 3) { ColorModel cm = new ColorModel() { ColorSpace = ColorSpace.YCbCr, Opaque = true }; image = new Image(cm, raster); } // Possibly CMYK or RGBA ? else { throw new NotSupportedException("Unsupported Color Mode: 4 Component Color Mode found."); } // If needed, convert centimeters to inches. Func <double, double> conv = x => Units == UnitType.Inches ? x : x / 2.54; image.DensityX = conv(XDensity); image.DensityY = conv(YDensity); //height = frame.Height; //width = frame.Width; } else { // JPEG Heirarchial Frame throw new NotSupportedException("Unsupported Codec Type: Hierarchial JPEG"); } break; // Only SOF0 (baseline) and SOF2 (progressive) are supported by FJCore case JPEGMarker.SOF1: case JPEGMarker.SOF3: case JPEGMarker.SOF5: case JPEGMarker.SOF6: case JPEGMarker.SOF7: case JPEGMarker.SOF9: case JPEGMarker.SOF10: case JPEGMarker.SOF11: case JPEGMarker.SOF13: case JPEGMarker.SOF14: case JPEGMarker.SOF15: throw new NotSupportedException("Unsupported codec type."); default: break; // ignore } #endregion switch over markers if (haveMarker) { haveMarker = false; } else { try { marker = jpegReader.GetNextMarker(); } catch (System.IO.EndOfStreamException) { break; /* done reading the file */ } } } DecodedJpeg result = new DecodedJpeg(image, headers); return(result); }
private void AddExifProperties (JpegHeader header) { Tiff.Header ifd = header.GetExifHeader (); if (ifd == null) return; //ifd.Dump ("foo"); // Uncomment to debug string str; Tiff.DirectoryEntry entry; // Add IFD 0 properies str = GetExifString (ifd.Directory, Tiff.TagId.Model); AddProperty (Beagle.Property.New ("exif:Model", str)); str = GetExifString (ifd.Directory, Tiff.TagId.ImageDescription); AddProperty (Beagle.Property.New ("exif:ImageDescription", str)); try { entry = ifd.Directory.Lookup (Tiff.TagId.DateTime); if (entry != null) // Assume datetime stored in the images are local times AddProperty (Beagle.Property.NewDate ("exif:DateTime", entry.ValueAsDate.ToUniversalTime ())); } catch (FormatException) { Logger.Log.Debug ("EXIF DateTime '{0}' is invalid.", GetExifString (ifd.Directory, Tiff.TagId.DateTime)); } catch (ArgumentOutOfRangeException) { Logger.Log.Debug ("EXIF DateTime '{0}' is invalid.", GetExifString (ifd.Directory, Tiff.TagId.DateTime)); } str = GetExifString (ifd.Directory, Tiff.TagId.Copyright); AddProperty (Beagle.Property.New ("dc:rights", str)); // Add IFD 1 properties Tiff.SubdirectoryEntry subdir = (Tiff.SubdirectoryEntry) ifd.Directory.Lookup (Tiff.TagId.ExifIfdPointer); if (subdir == null) return; Tiff.ImageDirectory exif = subdir.Directory [0]; if (exif == null) return; entry = exif.Lookup (Tiff.TagId.UserComment); if (entry != null) AddProperty (Beagle.Property.New ("exif:UserComment", entry.UserCommentValue)); uint val = 0; entry = exif.Lookup (Tiff.TagId.PixelXDimension); if (entry != null) val = entry.ValueAsLong [0]; if (val > 0) { Width = (int) val; AddProperty (Beagle.Property.NewUnsearched ("exif:PixelXDimension", val)); } val = 0; entry = exif.Lookup (Tiff.TagId.PixelYDimension); if (entry != null) val = entry.ValueAsLong [0]; if (val > 0) { Height = (int) val; AddProperty (Beagle.Property.NewUnsearched ("exif:PixelYDimension", val)); } str = GetExifString (exif, Tiff.TagId.ISOSpeedRatings); AddProperty (Beagle.Property.NewUnsearched ("exif:ISOSpeedRatings", str)); str = GetExifString (exif, Tiff.TagId.ShutterSpeedValue); AddProperty (Beagle.Property.NewUnsearched ("exif:ShutterSpeedValue", str)); str = GetExifString (exif, Tiff.TagId.ExposureTime); if (! String.IsNullOrEmpty (str)) AddProperty (Beagle.Property.NewUnsearched ("exif:ExposureTime", str + " sec.")); double rational_val; rational_val = GetExifRational (exif, Tiff.TagId.FNumber); if (rational_val > 0) AddProperty (Beagle.Property.NewUnsearched ("exif:FNumber", String.Format ("f/{0}", rational_val))); rational_val = GetExifRational (exif, Tiff.TagId.ApertureValue); if (rational_val > 0) AddProperty (Beagle.Property.NewUnsearched ("exif:ApertureValue", rational_val)); rational_val = GetExifRational (exif, Tiff.TagId.FocalLength); if (rational_val > 0) AddProperty (Beagle.Property.NewUnsearched ("exif:FocalLength", String.Format ("{0} mm", rational_val))); entry = exif.Lookup (Tiff.TagId.Flash); if (entry != null) { ushort flash = entry.ShortValue [0]; AddProperty (Beagle.Property.NewUnsearched ("exif:Flash", GetFlashString (flash))); } }
private void AddJfifProperties(JpegHeader header) { string comment = header.GetJFIFComment(); AddProperty(Beagle.Property.New("jfif:Comment", comment)); }
private void AddXmpProperties (JpegHeader header) { XmpFile xmp = header.GetXmp (); if (xmp != null) AddXmpProperties (xmp); }
private void AddIptcProperties (JpegHeader header) { IptcFile iptc = header.GetIptc (); if (iptc == null) return; foreach (DataSet data in iptc.Sets) { switch (data.ID) { case DataSetID.ContentLocationName: AddProperty (Beagle.Property.New ("iptc:location", data.XmpObject)); break; case DataSetID.CaptionAbstract: AddProperty (Beagle.Property.New ("iptc:caption", data.XmpObject)); break; case DataSetID.Keywords: AddProperty (Beagle.Property.NewKeyword ("iptc:keyword", data.XmpObject)); AddProperty (Beagle.Property.NewUnstored ("image:tag", data.XmpObject)); break; default: // FIXME: Anything else to index ? //Log.Debug ("Ignoring {0} = [{1}]", data.ID, data.XmpObject); break; } } }
// FIXME: This is not particularly efficient protected override void PullImageProperties () { JpegHeader header = new JpegHeader (Stream); AddJfifProperties (header); AddExifProperties (header); AddXmpProperties (header); AddIptcProperties (header); Finished (); // That's all folks... }
private void SaveMetaData (System.IO.Stream input, System.IO.Stream output) { JpegHeader header = new JpegHeader (input); UpdateMeta (); // Console.WriteLine ("updated metadata"); header.SetExif (this.ExifData); // Console.WriteLine ("set exif"); if (xmp != null) header.SetXmp (xmp); // Console.WriteLine ("set xmp"); header.Save (output); // Console.WriteLine ("saved"); }
private void AddJfifProperties (JpegHeader header) { string comment = header.GetJFIFComment (); AddProperty (Beagle.Property.New ("jfif:Comment", comment)); }