package imaging import ( "bytes" "encoding/binary" ) const ( tiffOrientationTag = 0x0112 tiffTypeShort = 3 tiffHeaderSize = 8 tiffEntrySize = 12 tiffMagic = 42 uprightOrientation = 1 maxOrientation = 8 ) var exifHeader = []byte("Exif\x00\x00") func exifOrientation(payload []byte) (uint16, bool) { tiff := bytes.TrimPrefix(payload, exifHeader) if len(tiff) < tiffHeaderSize { return 0, false } var order binary.ByteOrder switch string(tiff[:2]) { case "II": order = binary.LittleEndian case "MM": order = binary.BigEndian default: return 0, false } if order.Uint16(tiff[2:]) != tiffMagic { return 0, false } ifd := int(order.Uint32(tiff[4:])) if ifd < tiffHeaderSize || ifd+2 > len(tiff) { return 0, false } count := int(order.Uint16(tiff[ifd:])) for i := range count { entry := ifd + 2 + i*tiffEntrySize if entry+tiffEntrySize > len(tiff) { return 0, false } if order.Uint16(tiff[entry:]) != tiffOrientationTag || order.Uint16(tiff[entry+2:]) != tiffTypeShort { continue } value := order.Uint16(tiff[entry+8:]) if value < uprightOrientation || value > maxOrientation { return 0, false } return value, true } return 0, false } func needsOrientation(orientation uint16) bool { return orientation > uprightOrientation } func orientationOnlyTIFF(orientation uint16) []byte { tiff := make([]byte, 0, tiffHeaderSize+2+tiffEntrySize+4) tiff = append(tiff, 'M', 'M') tiff = binary.BigEndian.AppendUint16(tiff, tiffMagic) tiff = binary.BigEndian.AppendUint32(tiff, tiffHeaderSize) tiff = binary.BigEndian.AppendUint16(tiff, 1) tiff = binary.BigEndian.AppendUint16(tiff, tiffOrientationTag) tiff = binary.BigEndian.AppendUint16(tiff, tiffTypeShort) tiff = binary.BigEndian.AppendUint32(tiff, 1) tiff = binary.BigEndian.AppendUint16(tiff, orientation) tiff = binary.BigEndian.AppendUint16(tiff, 0) return binary.BigEndian.AppendUint32(tiff, 0) }