Metadata-Version: 2.4
Name: j-gif
Version: 0.4.1
Classifier: Development Status :: 4 - Beta
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Rust
License-File: LICENSE
License-File: THIRD-PARTY-NOTICES.txt
Summary: Screen recording to GIF for Python, implemented in Rust (HDR-correct DXGI capture with GDI fallback, JPEG-backed frame store, no GIL contention)
Keywords: gif,screen-recording,screen-capture,windows,rust
Author: JYAARU
License-Expression: MIT
Requires-Python: >=3.11
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM

# j-gif

Screen recording to GIF for Python, implemented in Rust.

Frames are captured through DXGI Desktop Duplication (via hdrcapture, so HDR
highlights are tone-mapped instead of clipped) with Win32 GDI (BitBlt) as the
fallback, compressed to JPEG and kept in a native frame store, then encoded to
GIF -- all on native threads, so the GIL is never held during recording or export.

A process can hold only one DXGI duplication per monitor. `RecordSession` opens its
own on the recording thread, so release any other session first, or pass
`prefer_dxgi=False` to record with GDI only.

Opening the DXGI session takes around 100 ms. To start recording without that delay,
prepare the session while the recording UI is up and begin it later:

```python
session = gifrecorder.RecordSession.prepare()        # builds the DXGI session now
session.begin(store, left, top, width, height, fps)  # first frame arrives immediately
```

- `FrameStore` -- accepts BGRA/RGB frames, stores them JPEG-compressed, exports GIF
- `FrameDecoder` -- background decoding for playback over a bounded channel
- `RecordSession` -- recording state machine (recording / paused / stopped)

The distribution is `j-gif`; the module imports as `gifrecorder`.

```python
import gifrecorder

store = gifrecorder.FrameStore(width, height, fps, jpeg_quality=90)
store.push_bgra(bgra_bytes, elapsed_ms)      # once per captured frame
store.export_gif("out.gif", repeat=0)
```

Playback can start directly at a frame without decoding earlier JPEGs:

```python
decoder = store.start_decoder(display_w=640, display_h=360, start_frame=100)
try:
    frame = decoder.next_frame()  # (RGB bytes, original elapsed_ms), or None
finally:
    decoder.stop()
```

`start_frame` defaults to zero. An index at or beyond the end produces an empty
decoder. `total_frames` counts frames from the chosen start to the end, and
`fetched_count` starts at zero. Timestamps remain relative to the original recording.
This parameter is available in j-gif 0.3.1 and later.

Windows x86_64 or ARM64, CPython 3.11+ (abi3). Part of
[jietuba](https://github.com/1003129155/jietuba). MIT licensed.

