|
| 1 | +# Owned image objects |
| 2 | + |
| 3 | +Version 0.84 adds Bun `Frame.makeImage`, `Camera.captureImageAsync`/`captureImage` |
| 4 | +and `captureFocusLockedImageAsync`/`captureFocusLockedImage`. They produce |
| 5 | +`CapturedImage` instances with independent compact pixels rather than retained |
| 6 | +camera buffers. Main/lores RGB/BGR/RGBX/BGRX, planar/semi-planar YUV420, packed422 |
| 7 | +and RGB16 sources reuse the existing checked native copy/conversion paths. |
| 8 | +Request callbacks also expose `makeImage`; their scoped request expires while |
| 9 | +the copied image remains usable. Capture selection keeps existing flush/drop/ |
| 10 | +SyncReady and CAF restoration semantics. |
| 11 | + |
| 12 | +Default precision follows the source: RGB16 remains sixteen bits; other inputs |
| 13 | +produce RGB8. `bits: 8` explicitly reduces word sources, and `bits: 16` rejects |
| 14 | +an eight-bit capture rather than inventing sensor precision. Each capture makes |
| 15 | +one independent native copy into owned Bun bytes. Geometry comes from the native |
| 16 | +stream descriptor. The scalar `sourceMetadata` snapshot, including its crop, is |
| 17 | +frozen, as is the source color description. This is source provenance; cropping |
| 18 | +an image does not change the recorded sensor ROI, and copied RGB bytes no longer |
| 19 | +have the source stream's packed YUV layout. Full/vendor metadata catalogs remain |
| 20 | +available from the original request. |
| 21 | + |
| 22 | +```ts |
| 23 | +using image = await camera.captureImage({ stream: 'main' }) |
| 24 | +await camera.close() |
| 25 | +using crop = image.crop(10, 10, 320, 240) |
| 26 | +using rgba16 = crop.convert({ format: 'rgba', bits: 16, endian: 'big' }) |
| 27 | +await rgba16.saveAsync('crop.png') |
| 28 | +``` |
| 29 | + |
| 30 | +Images expose immutable geometry/format/stride information, `getPixel` (RGBA8), |
| 31 | +`getPixel16` (RGBA16), `copyPixels`, `clone`, checked `crop`/`convert`, `encode`, |
| 32 | +synchronous atomic `save`, joined staged `saveAsync`, `close` and `Symbol.dispose`. |
| 33 | +Returned pixel copies are independent and writable. Closing an image releases |
| 34 | +its private Bun reference; it does not invalidate other images or returned |
| 35 | +copies. Already admitted save jobs retain their own input reference and can |
| 36 | +complete after source closure. Standalone image jobs belong to their caller, |
| 37 | +independently of the source camera's lifetime. |
| 38 | + |
| 39 | +`CapturedImage.fromRaster` copies checked gray/RGB/RGBA8/16 data with explicit |
| 40 | +endianness and optional row padding. Caller property accessors are consumed |
| 41 | +before native access, and intrinsic typed-array properties detect detached or |
| 42 | +misrepresented buffers. Conversion uses Home's new checked integer view: |
| 43 | +8-to-16 byte replication, 16-to-8 high-byte reduction, native-precision integer |
| 44 | +luma and explicit alpha dropping, without gamma/gamut conversion/compositing. |
| 45 | +Identical formats copy active rows. There is no resampling or hidden quality |
| 46 | +reduction. Converted/cropped/source pixels and encoded output are limited to |
| 47 | +256 MiB by the raster API; allocator scratch is additional. |
| 48 | + |
| 49 | +JPEG/PNG/BMP/TIFF/PPM/GIF reuse Home encoders. PNG/TIFF/PPM retain appropriate |
| 50 | +word precision; JPEG/BMP/GIF reduce to their supported representation. JPEG and |
| 51 | +PPM reject RGBA until an explicit RGB conversion is requested. GIF thresholds |
| 52 | +alpha as documented in gif.md. Gray pixels reject RGB ICC profiles. Other RGB |
| 53 | +ICC/explicit Exif options retain the existing validation; built-in sRGB requires |
| 54 | +a matching source declaration. `fromRaster.colorSpace` declares interpretation |
| 55 | +without converting pixels. The color values remain caller-owned assertions. |
| 56 | + |
| 57 | +An image object has no live capture request. Its bare saves default to no Exif, |
| 58 | +matching an independent image save; typed/raw caller Exif is supported without |
| 59 | +automatic capture fields. `exif: true` or `captureMetadata: true` explicitly |
| 60 | +reject. Request encoding/file APIs retain their existing request-derived Exif |
| 61 | +defaults. Raw sensor output still requires the calibrated DNG/request APIs. |
| 62 | + |
| 63 | +`saveAsync` reserves the existing bounded native file owner before yielding, |
| 64 | +then stages privately and joins publication/disposal. The shared factory admits |
| 65 | +at most 32 owners. Cancellation before publication preserves the destination; |
| 66 | +the native publication claim rejects late cancellation. The 30-second default |
| 67 | +deadline is rechecked after encoding. Encoding is synchronous on the Bun owner; |
| 68 | +native file I/O is asynchronous. This is not a new background codec worker. |
| 69 | + |
| 70 | +Zig exposes `Frame.makeImage(allocator, stream, bits)` returning |
| 71 | +`ImagePixels.Owned`; `null` selects native precision. Deinitialize that independent |
| 72 | +owner explicitly. `ImagePixels.View`/`Owned.copy` provide checked word conversion |
| 73 | +and cropped copies; request metadata can be copied separately before release. |
| 74 | +C uses borrowed `zc_raster` descriptors (the existing 48-byte raster layout), |
| 75 | +`zc_raster_convert`/`crop` size queries and copies, `zc_raster_pixel16`, owned-blob |
| 76 | +`zc_raster_encode`, atomic `zc_raster_save` and staged |
| 77 | +`zc_image_file_prepare_raster`. Native calls consume pixel pointers synchronously |
| 78 | +and retain none. The existing public ABI layouts and version remain unchanged. |
| 79 | + |
| 80 | +Home's Image API additionally receives corrected deep frame/palette cloning, |
| 81 | +Color16 access and transactional main/frame conversion, replacing uninitialized |
| 82 | +sixteen-bit destinations and black source conversions. Indexed source expansion |
| 83 | +is shared with PNG/GIF; indexed destinations explicitly reject. Home's portable |
| 84 | +view and independent test fixtures are reused verbatim here. |
| 85 | + |
| 86 | +The portable matrix checks 576 independent C-reference fixtures per pinned/ |
| 87 | +development Zig Debug/ReleaseSafe build. Bun tests cover all processed main/lores |
| 88 | +sources, lifetime independence, conversion, source detachment/accessors, callback/ |
| 89 | +CAF images, explicit Exif/ICC, save cancellation/GC/late claims and bounded burst |
| 90 | +admission/reuse. Independent libpng checks every encoded gray/RGB/RGBA8/16 byte, |
| 91 | +word, alpha sample and byte order. C/Zig tests check bounds, overlap, no-prefix |
| 92 | +copies, blob ownership and request/camera retirement. These tests are software |
| 93 | +evidence, not physical sensor quality, format acceptance or camera performance. |
| 94 | + |
| 95 | +Further image transforms/resizing, temporary-mode image conveniences, palette/ |
| 96 | +float/gamut conversion, general external image decoding and complete animation/ |
| 97 | +image-object semantics remain work. The full Picamera2 parity goal remains open. |
0 commit comments