private static Dictionary <MetadataSection, Dictionary <ushort, MetadataEntry> > CreateTagDictionary( Document doc, IDictionary <MetadataKey, MetadataEntry> entries, ExifColorSpace exifColorSpace) { Dictionary <MetadataSection, Dictionary <ushort, MetadataEntry> > metadataEntries = new Dictionary <MetadataSection, Dictionary <ushort, MetadataEntry> > { { MetadataSection.Image, new Dictionary <ushort, MetadataEntry> { { MetadataKeys.Image.Orientation.TagId, new MetadataEntry(MetadataKeys.Image.Orientation, TagDataType.Short, MetadataHelpers.EncodeShort(TiffConstants.Orientation.TopLeft)) } } }, { MetadataSection.Exif, new Dictionary <ushort, MetadataEntry>() } }; // Add the image size tags. if (IsUncompressedImage(entries)) { Dictionary <ushort, MetadataEntry> imageSection = metadataEntries[MetadataSection.Image]; imageSection.Add(MetadataKeys.Image.ImageWidth.TagId, new MetadataEntry(MetadataKeys.Image.ImageWidth, TagDataType.Long, MetadataHelpers.EncodeLong((uint)doc.Width))); imageSection.Add(MetadataKeys.Image.ImageLength.TagId, new MetadataEntry(MetadataKeys.Image.ImageLength, TagDataType.Long, MetadataHelpers.EncodeLong((uint)doc.Height))); entries.Remove(MetadataKeys.Image.ImageWidth); entries.Remove(MetadataKeys.Image.ImageLength); // These tags should not be included in uncompressed images. entries.Remove(MetadataKeys.Exif.PixelXDimension); entries.Remove(MetadataKeys.Exif.PixelYDimension); } else { Dictionary <ushort, MetadataEntry> exifSection = metadataEntries[MetadataSection.Exif]; exifSection.Add(MetadataKeys.Exif.PixelXDimension.TagId, new MetadataEntry(MetadataKeys.Exif.PixelXDimension, TagDataType.Long, MetadataHelpers.EncodeLong((uint)doc.Width))); exifSection.Add(MetadataKeys.Exif.PixelYDimension.TagId, new MetadataEntry(MetadataKeys.Exif.PixelYDimension, TagDataType.Long, MetadataHelpers.EncodeLong((uint)doc.Height))); entries.Remove(MetadataKeys.Exif.PixelXDimension); entries.Remove(MetadataKeys.Exif.PixelYDimension); // These tags should not be included in compressed images. entries.Remove(MetadataKeys.Image.ImageWidth); entries.Remove(MetadataKeys.Image.ImageLength); } // Add the EXIF color space tag. if (!entries.ContainsKey(MetadataKeys.Exif.ColorSpace)) { metadataEntries[MetadataSection.Exif].Add(MetadataKeys.Exif.ColorSpace.TagId, new MetadataEntry(MetadataKeys.Exif.ColorSpace, TagDataType.Short, MetadataHelpers.EncodeShort((ushort)exifColorSpace))); } foreach (KeyValuePair <MetadataKey, MetadataEntry> kvp in entries) { MetadataEntry entry = kvp.Value; MetadataSection section = entry.Section; if (section == MetadataSection.Image && !ExifTagHelper.CanWriteImageSectionTag(entry.TagId)) { continue; } if (metadataEntries.TryGetValue(section, out Dictionary <ushort, MetadataEntry> values)) { if (!values.ContainsKey(entry.TagId)) { values.Add(entry.TagId, entry); } } else { metadataEntries.Add(section, new Dictionary <ushort, MetadataEntry> { { entry.TagId, entry } }); } } AddVersionEntries(ref metadataEntries); return(metadataEntries); }
private static IFDEntryInfo CreateIFDList(Dictionary <ushort, MetadataEntry> tags, long startOffset) { List <IFDEntry> ifdEntries = new List <IFDEntry>(tags.Count); // Leave room for the tag count, tags and next IFD offset. long ifdDataOffset = startOffset + sizeof(ushort) + ((long)tags.Count * IFDEntry.SizeOf) + sizeof(uint); foreach (KeyValuePair <ushort, MetadataEntry> item in tags.OrderBy(i => i.Key)) { MetadataEntry entry = item.Value; uint count; switch (entry.Type) { case TagDataType.Byte: case TagDataType.Ascii: case TagDataType.SByte: case TagDataType.Undefined: count = (uint)entry.LengthInBytes; break; case TagDataType.Short: case TagDataType.SShort: count = (uint)entry.LengthInBytes / 2; break; case TagDataType.Long: case TagDataType.SLong: case TagDataType.Float: count = (uint)entry.LengthInBytes / 4; break; case TagDataType.Rational: case TagDataType.SRational: case TagDataType.Double: count = (uint)entry.LengthInBytes / 8; break; default: throw new InvalidOperationException("Unexpected tag type."); } if (TagDataTypeUtil.ValueFitsInOffsetField(entry.Type, count)) { uint packedOffset = 0; byte[] data = entry.GetDataReadOnly(); // The data is always in little-endian byte order. switch (data.Length) { case 1: packedOffset |= data[0]; break; case 2: packedOffset |= data[0]; packedOffset |= (uint)data[1] << 8; break; case 3: packedOffset |= data[0]; packedOffset |= (uint)data[1] << 8; packedOffset |= (uint)data[2] << 16; break; case 4: packedOffset |= data[0]; packedOffset |= (uint)data[1] << 8; packedOffset |= (uint)data[2] << 16; packedOffset |= (uint)data[3] << 24; break; default: throw new InvalidOperationException("data.Length must be in the range of [1-4]."); } ifdEntries.Add(new IFDEntry(entry.TagId, entry.Type, count, packedOffset)); } else { ifdEntries.Add(new IFDEntry(entry.TagId, entry.Type, count, (uint)ifdDataOffset)); ifdDataOffset += entry.LengthInBytes; // The IFD offsets must begin on a WORD boundary. if ((ifdDataOffset & 1) == 1) { ifdDataOffset++; } } } return(new IFDEntryInfo(ifdEntries, startOffset, ifdDataOffset)); }