internal static bool TryDecodeRational(MetadataEntry entry, out double value) { uint numerator; uint denominator; if (entry.Type != TagDataType.Rational || entry.LengthInBytes != 8) { value = 0.0; return(false); } byte[] data = entry.GetDataReadOnly(); numerator = (uint)(data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24)); denominator = (uint)(data[4] | (data[5] << 8) | (data[6] << 16) | (data[7] << 24)); if (denominator == 0) { // Avoid division by zero. value = 0.0; return(false); } value = (double)numerator / denominator; return(true); }
internal static bool TryDecodeShort(MetadataEntry entry, out ushort value) { if (entry.Type != TagDataType.Short || entry.LengthInBytes != 2) { value = 0; return(false); } byte[] data = entry.GetDataReadOnly(); value = (ushort)(data[0] | (data[1] << 8)); return(true); }
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; // Some applications may write EXIF fields with a count of zero. // See https://github.com/0xC0000054/pdn-webp/issues/6. if (count > 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)); }