first commit
This commit is contained in:
117
docs/media/image/exif/src/binary/reader/byte-reader.md
Normal file
117
docs/media/image/exif/src/binary/reader/byte-reader.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# ByteReader
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Provides a low-level, bounds-checked binary reader for TIFF/EXIF byte streams. It wraps a `Uint8Array` with a configurable byte order and exposes typed read methods for all TIFF primitive types. The runtime-agnostic implementation avoids Node.js `Buffer` and browser-specific APIs, relying solely on `DataView` and standard typed arrays.
|
||||
|
||||
## Features
|
||||
|
||||
- Big-endian and little-endian support with runtime `setByteOrder()` switching
|
||||
- Full TIFF primitive coverage: uint8/16/32, int16/32, float32/64, rational, signed rational
|
||||
- Bounds-checked reads that throw `ExifError` with `EXIF.PARSE_ERROR` on overflow
|
||||
- String reads with null-termination handling (`readString`, `readNullTermString`)
|
||||
- `slice()` factory that creates a sub-reader sharing the same byte order
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { ByteReader } from "@suaveplan/exif/binary";
|
||||
|
||||
const data = new Uint8Array([0x4D, 0x4D, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x08]);
|
||||
const reader = new ByteReader(data, "BE");
|
||||
|
||||
const magic = reader.readUint16(2); // 0x002A
|
||||
const ifdOffset = reader.readUint32(4); // 8
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { ByteReader } from "@suaveplan/exif/binary";
|
||||
|
||||
// Switch byte order mid-stream (e.g. after reading TIFF header)
|
||||
const reader = new ByteReader(tiffBuffer, "BE");
|
||||
const bom = reader.readUint16(0);
|
||||
if (bom === 0x4949) reader.setByteOrder("LE"); // Intel = little-endian
|
||||
|
||||
// Read a RATIONAL (8 bytes: numerator + denominator)
|
||||
const exposureTime = reader.readRational(offset);
|
||||
console.log(`${exposureTime.numerator}/${exposureTime.denominator}`);
|
||||
|
||||
// Sub-slice for IFD parsing
|
||||
const ifdReader = reader.slice(ifdOffset, ifdOffset + ifdSize);
|
||||
const entryCount = ifdReader.readUint16(0);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `constructor(data: Uint8Array, byteOrder?: ByteOrder): ByteReader`
|
||||
|
||||
Creates a new reader wrapping `data`. Default `byteOrder` is `"BE"` (big-endian).
|
||||
|
||||
### `setByteOrder(order: ByteOrder): void`
|
||||
|
||||
Switches the active byte order for all subsequent reads.
|
||||
|
||||
### `get length: number`
|
||||
|
||||
Returns the total byte length of the underlying buffer.
|
||||
|
||||
### `readUint8(offset: number): number`
|
||||
|
||||
Reads one unsigned byte at `offset`.
|
||||
|
||||
### `readUint16(offset: number): number`
|
||||
|
||||
Reads a 2-byte unsigned integer using the active byte order.
|
||||
|
||||
### `readUint32(offset: number): number`
|
||||
|
||||
Reads a 4-byte unsigned integer using the active byte order.
|
||||
|
||||
### `readInt16(offset: number): number`
|
||||
|
||||
Reads a 2-byte signed integer using the active byte order.
|
||||
|
||||
### `readInt32(offset: number): number`
|
||||
|
||||
Reads a 4-byte signed integer using the active byte order.
|
||||
|
||||
### `readFloat32(offset: number): number`
|
||||
|
||||
Reads a 4-byte IEEE 754 single-precision float using the active byte order.
|
||||
|
||||
### `readFloat64(offset: number): number`
|
||||
|
||||
Reads an 8-byte IEEE 754 double-precision float using the active byte order.
|
||||
|
||||
### `readBytes(offset: number, length: number): Uint8Array`
|
||||
|
||||
Returns a copy of `length` bytes starting at `offset`.
|
||||
|
||||
### `readString(offset: number, length: number): string`
|
||||
|
||||
Reads `length` bytes as a Latin-1 string, stopping at the first null byte.
|
||||
|
||||
### `readNullTermString(offset: number): string`
|
||||
|
||||
Scans forward from `offset` until a null byte, then reads the preceding bytes as a string.
|
||||
|
||||
### `readRational(offset: number): Rational`
|
||||
|
||||
Reads an 8-byte TIFF RATIONAL (two unsigned 32-bit integers: numerator then denominator).
|
||||
|
||||
### `readSRational(offset: number): Rational`
|
||||
|
||||
Reads an 8-byte TIFF SRATIONAL (two signed 32-bit integers).
|
||||
|
||||
### `slice(start: number, end: number): ByteReader`
|
||||
|
||||
Returns a new `ByteReader` over `data.slice(start, end)` with the same byte order.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
All read methods call `assertBounds` before touching `DataView` to ensure clear error messages on malformed input. The `view` is constructed from the array's `buffer`, `byteOffset`, and `byteLength` to correctly handle sliced `Uint8Array` inputs that do not start at offset 0 in their underlying `ArrayBuffer`. The `readString` and `readNullTermString` methods use Latin-1 (one byte per character) which matches TIFF/EXIF ASCII strings; UTF-8 decoding is not attempted here as EXIF ASCII tags are defined as 7-bit ASCII.
|
||||
Reference in New Issue
Block a user