public IFDEntry(ushort tag, ExifValueType type, uint count, uint offset) { Tag = tag; Type = type; Count = count; Offset = offset; }
/// <summary> /// Determines whether the values fit in the offset field. /// </summary> /// <param name="type">The type.</param> /// <param name="count">The count.</param> /// <returns> /// <see langword="true"/> if the values fit in the offset field; otherwise, <see langword="false"/>. /// </returns> public static bool ValueFitsInOffsetField(ExifValueType type, uint count) { switch (type) { case ExifValueType.Byte: case ExifValueType.Ascii: case ExifValueType.Undefined: case (ExifValueType)6: // SByte return(count <= 4); case ExifValueType.Short: case ExifValueType.SShort: return(count <= 2); case ExifValueType.Long: case ExifValueType.SLong: case ExifValueType.Float: case (ExifValueType)13: // IFD return(count <= 1); case ExifValueType.Rational: case ExifValueType.SRational: case ExifValueType.Double: default: return(false); } }
/// <summary> /// Gets the size in bytes of a <see cref="TagDataType"/> value. /// </summary> /// <param name="type">The tag type.</param> /// <returns> /// The size of the value in bytes. /// </returns> public static int GetSizeInBytes(ExifValueType type) { switch (type) { case ExifValueType.Byte: case ExifValueType.Ascii: case ExifValueType.Undefined: case (ExifValueType)6: // SByte return(1); case ExifValueType.Short: case ExifValueType.SShort: return(2); case ExifValueType.Long: case ExifValueType.SLong: case ExifValueType.Float: case (ExifValueType)13: // IFD return(4); case ExifValueType.Rational: case ExifValueType.SRational: case ExifValueType.Double: return(8); default: return(0); } }
private string GetValueStringFromOffset() { string valueString; ExifValueType type = entry.Type; uint count = entry.Count; uint offset = entry.Offset; if (count == 0) { return(string.Empty); } int typeSizeInBytes = ExifValueTypeUtil.GetSizeInBytes(type); if (typeSizeInBytes == 1) { byte[] bytes = new byte[count]; if (offsetIsBigEndian) { switch (count) { case 1: bytes[0] = (byte)((offset >> 24) & 0x000000ff); break; case 2: bytes[0] = (byte)((offset >> 24) & 0x000000ff); bytes[1] = (byte)((offset >> 16) & 0x000000ff); break; case 3: bytes[0] = (byte)((offset >> 24) & 0x000000ff); bytes[1] = (byte)((offset >> 16) & 0x000000ff); bytes[2] = (byte)((offset >> 8) & 0x000000ff); break; case 4: bytes[0] = (byte)((offset >> 24) & 0x000000ff); bytes[1] = (byte)((offset >> 16) & 0x000000ff); bytes[2] = (byte)((offset >> 8) & 0x000000ff); bytes[3] = (byte)(offset & 0x000000ff); break; } } else { switch (count) { case 1: bytes[0] = (byte)(offset & 0x000000ff); break; case 2: bytes[0] = (byte)(offset & 0x000000ff); bytes[1] = (byte)((offset >> 8) & 0x000000ff); break; case 3: bytes[0] = (byte)(offset & 0x000000ff); bytes[1] = (byte)((offset >> 8) & 0x000000ff); bytes[2] = (byte)((offset >> 16) & 0x000000ff); break; case 4: bytes[0] = (byte)(offset & 0x000000ff); bytes[1] = (byte)((offset >> 8) & 0x000000ff); bytes[2] = (byte)((offset >> 16) & 0x000000ff); bytes[3] = (byte)((offset >> 24) & 0x000000ff); break; } } if (type == ExifValueType.Ascii) { valueString = Encoding.UTF8.GetString(bytes).TrimEnd('\0'); } else if (count == 1) { valueString = bytes[0].ToString(CultureInfo.InvariantCulture); } else { StringBuilder builder = new(); uint lastItemIndex = count - 1; for (int i = 0; i < count; i++) { builder.Append(bytes[i].ToString(CultureInfo.InvariantCulture)); if (i < lastItemIndex) { builder.Append(','); } } valueString = builder.ToString(); } } else if (typeSizeInBytes == 2) { ushort[] values = new ushort[count]; if (offsetIsBigEndian) { switch (count) { case 1: values[0] = (ushort)((offset >> 16) & 0x0000ffff); break; case 2: values[0] = (ushort)((offset >> 16) & 0x0000ffff); values[1] = (ushort)(offset & 0x0000ffff); break; } } else { switch (count) { case 1: values[0] = (ushort)(offset & 0x0000ffff); break; case 2: values[0] = (ushort)(offset & 0x0000ffff); values[1] = (ushort)((offset >> 16) & 0x0000ffff); break; } } if (count == 1) { switch (type) { case ExifValueType.SShort: valueString = ((short)values[0]).ToString(CultureInfo.InvariantCulture); break; case ExifValueType.Short: default: valueString = values[0].ToString(CultureInfo.InvariantCulture); break; } } else { switch (type) { case ExifValueType.SShort: valueString = ((short)values[0]).ToString(CultureInfo.InvariantCulture) + "," + ((short)values[1]).ToString(CultureInfo.InvariantCulture); break; case ExifValueType.Short: default: valueString = values[0].ToString(CultureInfo.InvariantCulture) + "," + values[1].ToString(CultureInfo.InvariantCulture); break; } } } else { valueString = offset.ToString(CultureInfo.InvariantCulture); } return(valueString); }
public unsafe byte[] GetValueBytesFromOffset() { if (!OffsetFieldContainsValue) { return(null); } ExifValueType type = entry.Type; uint count = entry.Count; uint offset = entry.Offset; if (count == 0) { return(Array.Empty <byte>()); } // Paint.NET always stores data in little-endian byte order. byte[] bytes; if (type == ExifValueType.Byte || type == ExifValueType.Ascii || type == (ExifValueType)6 || // SByte type == ExifValueType.Undefined) { bytes = new byte[count]; if (offsetIsBigEndian) { switch (count) { case 1: bytes[0] = (byte)((offset >> 24) & 0x000000ff); break; case 2: bytes[0] = (byte)((offset >> 24) & 0x000000ff); bytes[1] = (byte)((offset >> 16) & 0x000000ff); break; case 3: bytes[0] = (byte)((offset >> 24) & 0x000000ff); bytes[1] = (byte)((offset >> 16) & 0x000000ff); bytes[2] = (byte)((offset >> 8) & 0x000000ff); break; case 4: bytes[0] = (byte)((offset >> 24) & 0x000000ff); bytes[1] = (byte)((offset >> 16) & 0x000000ff); bytes[2] = (byte)((offset >> 8) & 0x000000ff); bytes[3] = (byte)(offset & 0x000000ff); break; } } else { switch (count) { case 1: bytes[0] = (byte)(offset & 0x000000ff); break; case 2: bytes[0] = (byte)(offset & 0x000000ff); bytes[1] = (byte)((offset >> 8) & 0x000000ff); break; case 3: bytes[0] = (byte)(offset & 0x000000ff); bytes[1] = (byte)((offset >> 8) & 0x000000ff); bytes[2] = (byte)((offset >> 16) & 0x000000ff); break; case 4: bytes[0] = (byte)(offset & 0x000000ff); bytes[1] = (byte)((offset >> 8) & 0x000000ff); bytes[2] = (byte)((offset >> 16) & 0x000000ff); bytes[3] = (byte)((offset >> 24) & 0x000000ff); break; } } } else if (type == ExifValueType.Short || type == ExifValueType.SShort) { int byteArrayLength = unchecked ((int)count) * sizeof(ushort); bytes = new byte[byteArrayLength]; fixed(byte *ptr = bytes) { ushort *ushortPtr = (ushort *)ptr; if (offsetIsBigEndian) { switch (count) { case 1: ushortPtr[0] = (ushort)((offset >> 16) & 0x0000ffff); break; case 2: ushortPtr[0] = (ushort)((offset >> 16) & 0x0000ffff); ushortPtr[1] = (ushort)(offset & 0x0000ffff); break; } } else { switch (count) { case 1: ushortPtr[0] = (ushort)(offset & 0x0000ffff); break; case 2: ushortPtr[0] = (ushort)(offset & 0x0000ffff); ushortPtr[1] = (ushort)((offset >> 16) & 0x0000ffff); break; } } } } else { bytes = new byte[4]; fixed(byte *ptr = bytes) { // The offset is stored as little-endian in memory. *(uint *)ptr = offset; } } return(bytes); }