From 6ec8dddf4610ae4e26f693877bb647b11f8a5231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gast=C3=B3n=20Zalba?= Date: Wed, 25 Jan 2023 17:02:44 -0300 Subject: [PATCH 1/9] Added missing options and improved tests --- .gitignore | 1 + .npmignore | 1 + src/index.ts | 30 ++++++++++++++++++++++++++++++ src/lib/shared-args.ts | 22 +++++++++++++++++++++- src/lib/still-camera.test.ts | 16 ++++++++++++++++ src/lib/still-camera.ts | 20 ++++++++++++++++++-- src/lib/stream-camera.test.ts | 15 +++++++++++++++ src/lib/stream-camera.ts | 8 ++++++-- 8 files changed, 108 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index ad90b97..5ce8b8d 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ stats.json # dev environments .vscode/* **/.DS_Store +test_images/*.jpeg diff --git a/.npmignore b/.npmignore index 87e583d..543b066 100644 --- a/.npmignore +++ b/.npmignore @@ -1,4 +1,5 @@ src/ +test_images/ yarn.lock tsconfig.json diff --git a/src/index.ts b/src/index.ts index b35ddd9..5853462 100644 --- a/src/index.ts +++ b/src/index.ts @@ -44,3 +44,33 @@ export enum AwbMode { Horizon = 'horizon', GreyWorld = 'greyworld', } + +export enum ImxfxMode { + None = 'none', + Negative = 'negative', + Solarise = 'solarise', + Sketch = 'sketch', + Denoise = 'denoise', + Emboss = 'emboss', + OilPaint = 'oilpaint', + Hatch = 'hatch', + GPen = 'gpen', + Pastel = 'pastel', + Watercolour = 'watercolour', + Film = 'film', + Blur = 'blur', + Saturation = 'saturation', + ColourSwap = 'colourswap', + WashedOut = 'washedout', + Posterise = 'posterise', + ColourPoint = 'colourpoint', + ColourBalance = 'colourbalance', + Cartoon = 'cartoon', +} + +export enum DynamicRange { + Off = 'off', + Low = 'low', + Medium = 'medium', + High = 'high' +} \ No newline at end of file diff --git a/src/lib/shared-args.ts b/src/lib/shared-args.ts index aa02fba..94eae40 100644 --- a/src/lib/shared-args.ts +++ b/src/lib/shared-args.ts @@ -94,5 +94,25 @@ export function getSharedArgs(options: StillOptions | StreamOptions): string[] { * Digital Gain */ ...(options.digitalGain ? ['--digitalgain', options.digitalGain.toString()] : []), + + /** + * Image Effect + */ + ...(options.imageEffect ? ['--imxfx', options.imageEffect.toString()] : []), + + /** + * Dynamic Range Control + */ + ...(options.dynamicRange ? ['--drc', options.dynamicRange] : []), + + /** + * Colour Effects + */ + ...(options.colourEffect ? ['--colfx', options.colourEffect.join(':')] : []), + + /** + * Video Stabilisation + */ + ...(options.videoStabilisation ? ['--vstab'] : []), ]; -} +} \ No newline at end of file diff --git a/src/lib/still-camera.test.ts b/src/lib/still-camera.test.ts index 9485e6a..04f42e4 100644 --- a/src/lib/still-camera.test.ts +++ b/src/lib/still-camera.test.ts @@ -1,9 +1,25 @@ +import * as fs from 'fs'; +import { performance } from 'perf_hooks'; + import StillCamera from './still-camera'; +const TEST_IMAGES_DIR = 'test_images'; + +if (!fs.existsSync(TEST_IMAGES_DIR)) { + fs.mkdirSync(TEST_IMAGES_DIR); +} + test('takeImage() returns JPEG', async () => { + + const t0 = performance.now(); + const stillCamera = new StillCamera(); const jpegImage = await stillCamera.takeImage(); + const t1 = performance.now(); + + const time = ((t1 - t0) / 1000).toFixed(2); + await fs.promises.writeFile(`test_images/stillCapture_(${time}-secs).jpeg`, jpegImage, 'binary'); expect(jpegImage.indexOf(StillCamera.jpegSignature)).toBe(0); }); diff --git a/src/lib/still-camera.ts b/src/lib/still-camera.ts index df7ee14..15793cb 100644 --- a/src/lib/still-camera.ts +++ b/src/lib/still-camera.ts @@ -1,4 +1,4 @@ -import { AwbMode, ExposureMode, Flip, Rotation } from '..'; +import { AwbMode, DynamicRange, ExposureMode, Flip, ImxfxMode, Rotation } from '..'; import { spawnPromise } from '../util'; import { getSharedArgs } from './shared-args'; @@ -19,6 +19,12 @@ export interface StillOptions { awbMode?: AwbMode; analogGain?: number; digitalGain?: number; + imageEffect?: ImxfxMode; + colourEffect?: [number, number]; // U,V + dynamicRange?: DynamicRange; + videoStabilisation?: boolean; + raw?: boolean; + quality?: number; } export default class StillCamera { @@ -48,12 +54,22 @@ export default class StillCamera { */ '--timeout', this.options.delay!.toString(), - + /** * Do not display preview overlay on screen */ '--nopreview', + /** + * RAW (Save Bayer Data) + */ + ...(this.options.raw ? ['--raw'] : []), + + /** + * JPEG Quality + */ + ...(this.options.quality ? ['--quality', this.options.quality.toString()] : []), + /** * Output to stdout */ diff --git a/src/lib/stream-camera.test.ts b/src/lib/stream-camera.test.ts index 22f1b6c..3d96bef 100644 --- a/src/lib/stream-camera.test.ts +++ b/src/lib/stream-camera.test.ts @@ -1,6 +1,17 @@ +import * as fs from 'fs'; +import { performance } from 'perf_hooks'; + import StreamCamera, { Codec } from './stream-camera'; +const TEST_IMAGES_DIR = 'test_images'; + +if (!fs.existsSync(TEST_IMAGES_DIR)) { + fs.mkdirSync(TEST_IMAGES_DIR); +} + test('Method takeImage() grabs JPEG from MJPEG stream', async () => { + const t0 = performance.now(); + const streamCamera = new StreamCamera({ codec: Codec.MJPEG, }); @@ -10,6 +21,10 @@ test('Method takeImage() grabs JPEG from MJPEG stream', async () => { const jpegImage = await streamCamera.takeImage(); await streamCamera.stopCapture(); + const t1 = performance.now(); + + const time = ((t1 - t0) / 1000).toFixed(2); + await fs.promises.writeFile(`test_images/streamCapture_(${time}-secs).jpeg`, jpegImage, 'binary'); expect(jpegImage.indexOf(StreamCamera.jpegSignature)).toBe(0); }); diff --git a/src/lib/stream-camera.ts b/src/lib/stream-camera.ts index 693ab3a..841d306 100644 --- a/src/lib/stream-camera.ts +++ b/src/lib/stream-camera.ts @@ -1,7 +1,7 @@ import { ChildProcessWithoutNullStreams, spawn } from 'child_process'; import { EventEmitter } from 'events'; import * as stream from 'stream'; -import { AwbMode, ExposureMode, Flip, Rotation } from '..'; +import { AwbMode, DynamicRange, ExposureMode, Flip, ImxfxMode, Rotation } from '..'; import { getSharedArgs } from './shared-args'; export enum Codec { @@ -40,6 +40,10 @@ export interface StreamOptions { awbMode?: AwbMode; analogGain?: number; digitalGain?: number; + imageEffect?: ImxfxMode; + colourEffect?: [number, number]; // U,V + dynamicRange?: DynamicRange; + videoStabilisation?: boolean; } declare interface StreamCamera { @@ -226,7 +230,7 @@ class StreamCamera extends EventEmitter { createStream() { const newStream = new stream.Readable({ - read: () => {}, + read: () => { }, }); this.streams.push(newStream); From c897e118994909294d3e599536ceb6cfbf9d8e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gast=C3=B3n=20Zalba?= Date: Wed, 25 Jan 2023 17:30:34 -0300 Subject: [PATCH 2/9] Updated README --- README.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/README.md b/README.md index 4bd419a..d053416 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,8 @@ Note that this example produces a raw H264 video. Wrapping it in a video contain - [`SensorMode`](#sensormode) - [`ExposureMode`](#exposuremode) - [`AwbMode`](#awbmode) +- [`DynamicRange`](#dynamicRange) +- [`ImageEffect`](#imageEffect) ## `StillCamera` @@ -263,6 +265,12 @@ const stillCamera = new StillCamera({ - [`awbMode: AwbMode`](#awbmode) - _Default: `AwbMode.Auto`_ - `analogGain: number` - _Default: `0`_ - `digitalGain: number` - _Default: `0`_ +- `quality: number` - _Default: `100`_ +- `colourEffect: [number, number]` - _Default: `[0,0]`_ +- [`imageEffect: ImxfxMode`](#imageeffect) - _Default: `ImxfxMode.None`_ +- [`dynamicRange: DynamicRange`](#dynamicrange) - _Default: `DynamicRange.Off`_ +- `videoStabilisation: boolean` - _Default: `false`_ +- `raw: boolean` - _Default: `false`_ ### `StillCamera.takeImage(): Promise` @@ -309,6 +317,10 @@ const streamCamera = new StreamCamera({ - [`awbMode: AwbMode`](#awbmode) - _Default: `AwbMode.Auto`_ - `analogGain: number` - _Default: `0`_ - `digitalGain: number` - _Default: `0`_ +- `colourEffect: [number, number]` - _Default: `[0,0]`_ +- [`imageEffect: ImxfxMode`](#imageeffect) - _Default: `ImxfxMode.None`_ +- [`dynamicRange: DynamicRange`](#dynamicrange) - _Default: `DynamicRange.Off`_ +- `videoStabilisation: boolean` - _Default: `false`_ ### `startCapture(): Promise` @@ -489,3 +501,45 @@ White balance mode options. ```javascript import { AwbMode } from 'pi-camera-connect'; ``` + +## `ImageEffect` + +Image Effect options. + +- `ImxfxMode.None` +- `ImxfxMode.Negative` +- `ImxfxMode.Solarise` +- `ImxfxMode.Sketch` +- `ImxfxMode.Denoise` +- `ImxfxMode.Emboss` +- `ImxfxMode.OilPaint` +- `ImxfxMode.Hatch` +- `ImxfxMode.GPen` +- `ImxfxMode.Pastel` +- `ImxfxMode.Watercolour` +- `ImxfxMode.Film` +- `ImxfxMode.Blur` +- `ImxfxMode.Saturation` +- `ImxfxMode.ColourSwap` +- `ImxfxMode.WashedOut` +- `ImxfxMode.Posterise` +- `ImxfxMode.ColourPoint` +- `ImxfxMode.ColourBalance` +- `ImxfxMode.Cartoon` + +```javascript +import { ImxfxMode } from 'pi-camera-connect'; +``` + +## `DynamicRange` + +Dynamic Range options. + +- `DynamicRange.Off` +- `DynamicRange.Low` +- `DynamicRange.Medium` +- `DynamicRange.High` + +```javascript +import { DynamicRange } from 'pi-camera-connect'; +``` \ No newline at end of file From cf00db07b204ed95348604e509aa5b6727476970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gast=C3=B3n=20Zalba?= Date: Sat, 4 Feb 2023 14:01:46 -0300 Subject: [PATCH 3/9] Added more missing options and HQ Camera mode --- README.md | 54 ++++++++++++++++++++++++++++++++-- src/index.ts | 18 ++++++++++-- src/lib/shared-args.ts | 57 ++++++++++++++++++++++++++++++++++-- src/lib/still-camera.test.ts | 1 - src/lib/still-camera.ts | 50 +++++++++++++++++++++++++++---- src/lib/stream-camera.ts | 35 ++++++++++++++++++++-- 6 files changed, 199 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index d053416..f421f60 100644 --- a/README.md +++ b/README.md @@ -263,6 +263,7 @@ const stillCamera = new StillCamera({ - `exposureCompensation: number` - _Range: `-10`-`10`; Default: `0`_ - [`exposureMode: ExposureMode`](#exposuremode) - _Default: `ExposureMode.Auto`_ - [`awbMode: AwbMode`](#awbmode) - _Default: `AwbMode.Auto`_ +- `awbGains: [number, number]` - _Default: `null`_ - `analogGain: number` - _Default: `0`_ - `digitalGain: number` - _Default: `0`_ - `quality: number` - _Default: `100`_ @@ -271,6 +272,12 @@ const stillCamera = new StillCamera({ - [`dynamicRange: DynamicRange`](#dynamicrange) - _Default: `DynamicRange.Off`_ - `videoStabilisation: boolean` - _Default: `false`_ - `raw: boolean` - _Default: `false`_ +- [`meteringMode`](#meteringMode) - _Default: `MeteringMode.Off`_ +- `thumbnail: [number, number, number] | 'none'` - _Default: `[64, 48, 35]`_ +- [`flickerMode`](#flickerMode) - _Default: `null`_ +- `burst: boolean` - _Default: `false`_ +- `roi: [number, number, number, number]` - _Default: `null`_ +- `statistics: boolean` - _Default: `false`_ ### `StillCamera.takeImage(): Promise` @@ -315,12 +322,17 @@ const streamCamera = new StreamCamera({ - `exposureCompensation: number` - _Range: `-10`-`10`; Default: `0`_ - [`exposureMode: ExposureMode`](#exposuremode) - _Default: `ExposureMode.Auto`_ - [`awbMode: AwbMode`](#awbmode) - _Default: `AwbMode.Auto`_ +- `awbGains: [number, number]` - _Default: `null`_ - `analogGain: number` - _Default: `0`_ - `digitalGain: number` - _Default: `0`_ - `colourEffect: [number, number]` - _Default: `[0,0]`_ - [`imageEffect: ImxfxMode`](#imageeffect) - _Default: `ImxfxMode.None`_ - [`dynamicRange: DynamicRange`](#dynamicrange) - _Default: `DynamicRange.Off`_ - `videoStabilisation: boolean` - _Default: `false`_ +- [`meteringMode`](#meteringMode) - _Default: `MeteringMode.Off`_ +- [`flickerMode`](#flickerMode) - _Default: `null`_ +- `roi: [number, number, number, number]` - _Default: `null`_ +- `statistics: boolean` - _Default: `false`_ ### `startCapture(): Promise` @@ -458,7 +470,19 @@ These are slightly different depending on the version of Raspberry Pi camera you | 4 | 1640x1232 | 4:3 | 0.1-40fps | Full | 2x2 | | 5 | 1640x922 | 16:9 | 0.1-40fps | Full | 2x2 | | 6 | 1280x720 | 16:9 | 40-90fps | Partial | 2x2 | -| 7 | 640x480 | 4:3 | 40-90fps | Partial | 2x2 | +| 7 | 640x480 | 4:3 | 40-200fps* | Partial | 2x2 | + +*For frame rates over 120fps, it is necessary to turn off automatic exposure and gain control using -ex off. Doing so should achieve the higher frame rates, but exposure time and gains will need to be set to fixed values supplied by the user. + +#### HQ Camera (IMX477): + +| Mode | Size | Aspect Ratio | Frame rates | FOV | Binning | +|------|---------------------|--------------|-------------|---------|-------------| +| 0 | automatic selection | | | | | +| 1 | 2028x1080 | 169:90 | 0.1-50fps | Partial | 2x2 binned | +| 2 | 2028x1520 | 4:3 | 0.1-50fps | Full | 2x2 binned | +| 3 | 4056x3040 | 4:3 | 0.005-10fps | Full | None | +| 4 | 1332x990 | 74:55 | 50.1-120fps | Partial | 2x2 binned | ## `ExposureMode` @@ -542,4 +566,30 @@ Dynamic Range options. ```javascript import { DynamicRange } from 'pi-camera-connect'; -``` \ No newline at end of file +``` + +## `MeteringMode` + +Dynamic Range options. + +- `MeteringMode.Average` +- `MeteringMode.Spot` +- `MeteringMode.Backlit` +- `MeteringMode.Matrix` + +```javascript +import { MeteringMode } from 'pi-camera-connect'; +``` + +## `FlickerMode` + +Dynamic Range options. + +- `FlickerMode.Off` +- `FlickerMode.Auto` +- `FlickerMode.50hz` +- `FlickerMode.60hz` + +```javascript +import { FlickerMode } from 'pi-camera-connect'; +``` diff --git a/src/index.ts b/src/index.ts index 5853462..c5486ce 100644 --- a/src/index.ts +++ b/src/index.ts @@ -72,5 +72,19 @@ export enum DynamicRange { Off = 'off', Low = 'low', Medium = 'medium', - High = 'high' -} \ No newline at end of file + High = 'high', +} + +export enum MeteringMode { + Average = 'average', + Spot = 'spot', + Backlit = 'backlit', + Matrix = 'matrix', +} + +export enum FlickerMode { + Off = 'off', + Auto = 'auto', + '50hz' = '50hz', + '60Hz' = '60hz', +} diff --git a/src/lib/shared-args.ts b/src/lib/shared-args.ts index 94eae40..6bb0621 100644 --- a/src/lib/shared-args.ts +++ b/src/lib/shared-args.ts @@ -66,12 +66,12 @@ export function getSharedArgs(options: StillOptions | StreamOptions): string[] { ...(options.saturation ? ['--saturation', options.saturation.toString()] : []), /** - * ISO + * ISO (100 to 800) */ ...(options.iso ? ['--ISO', options.iso.toString()] : []), /** - * EV Compensation + * EV Compensation (-10 to 10; default 0) */ ...(options.exposureCompensation ? ['--ev', options.exposureCompensation.toString()] : []), @@ -85,13 +85,24 @@ export function getSharedArgs(options: StillOptions | StreamOptions): string[] { */ ...(options.awbMode ? ['--awb', options.awbMode.toString()] : []), + /** + * Sets the blue and red channel gains if awbMode is Off + */ + ...(options.awbGains ? ['--awbgains', options.awbGains.toString()] : []), + /** * Analog Gain + * Sets the analog gain value directly on the sensor (floating point value from + * 1.0 to 8.0 for the OV5647 sensor on Camera Module V1, and 1.0 to 12.0 for the + * IMX219 sensor on Camera Module V2 and the IMX447 on the HQ Camera). */ ...(options.analogGain ? ['--analoggain', options.analogGain.toString()] : []), /** * Digital Gain + * Sets the digital gain value applied by the ISP + * (floating point value from 1.0 to 64.0, + * but values over about 4.0 willproduce overexposed images) */ ...(options.digitalGain ? ['--digitalgain', options.digitalGain.toString()] : []), @@ -107,12 +118,52 @@ export function getSharedArgs(options: StillOptions | StreamOptions): string[] { /** * Colour Effects + * The supplied U and V parameters (range 0 to 255) are applied to + * the U and Y channels of the image. For example, --colfx 128:128 + * should result in a monochrome image. */ ...(options.colourEffect ? ['--colfx', options.colourEffect.join(':')] : []), + /** + * Metering + * Specify the metering mode used for the preview and capture. + */ + ...(options.meteringMode ? ['--metering', options.meteringMode] : []), + + /** + * Flicker Avoid Mode + * Set a mode to compensate for lights flickering at the mains frequency, + * which can be seen as a dark horizontal band across an image. + * Flicker avoidance locks the exposure time to a multiple of the mains + * flicker frequency (8.33ms for 60Hz, or 10ms for 50Hz). + * This means that images can be noisier as the control algorithm has to + * increase the gain instead of exposure time should it wish for an + * intermediate exposure value. auto can be confused by external factors, + * therefore it is preferable to leave this setting off unless actually required. + */ + ...(options.flickerMode ? ['--flicker', options.flickerMode] : []), + /** * Video Stabilisation + * In video mode only, turn on video stabilization. */ ...(options.videoStabilisation ? ['--vstab'] : []), + + /** + * Statistics + * Force recomputation of statistics on stills capture pass. Digital gain and AWB are + * recomputed based on the actual capture frame statistics, + * rather than the preceding preview frame. + */ + ...(options.statistics ? ['--stats'] : []), + + /** + * Sensor region of interest + * Allows the specification of the area of the sensor to be used as + * the source for the preview and capture. This is defined as x,y for + * the top left corner, and a width and height, all values in + * normalised coordinates (0.0-1.0). + */ + ...(options.roi ? ['--roi', options.toString()] : []), ]; -} \ No newline at end of file +} diff --git a/src/lib/still-camera.test.ts b/src/lib/still-camera.test.ts index 04f42e4..c300fc4 100644 --- a/src/lib/still-camera.test.ts +++ b/src/lib/still-camera.test.ts @@ -10,7 +10,6 @@ if (!fs.existsSync(TEST_IMAGES_DIR)) { } test('takeImage() returns JPEG', async () => { - const t0 = performance.now(); const stillCamera = new StillCamera(); diff --git a/src/lib/still-camera.ts b/src/lib/still-camera.ts index 15793cb..44100a1 100644 --- a/src/lib/still-camera.ts +++ b/src/lib/still-camera.ts @@ -1,4 +1,13 @@ -import { AwbMode, DynamicRange, ExposureMode, Flip, ImxfxMode, Rotation } from '..'; +import { + AwbMode, + DynamicRange, + ExposureMode, + FlickerMode, + Flip, + ImxfxMode, + MeteringMode, + Rotation, +} from '..'; import { spawnPromise } from '../util'; import { getSharedArgs } from './shared-args'; @@ -17,6 +26,7 @@ export interface StillOptions { exposureCompensation?: number; exposureMode?: ExposureMode; awbMode?: AwbMode; + awbGains?: [number, number]; analogGain?: number; digitalGain?: number; imageEffect?: ImxfxMode; @@ -25,6 +35,12 @@ export interface StillOptions { videoStabilisation?: boolean; raw?: boolean; quality?: number; + statistics?: boolean; + thumbnail?: [number, number, number] | 'none'; // X, Y, Q + meteringMode?: MeteringMode; + flickerMode?: FlickerMode; + burst?: boolean; + roi?: [number, number, number, number]; // X, Y, W, H } export default class StillCamera { @@ -54,22 +70,46 @@ export default class StillCamera { */ '--timeout', this.options.delay!.toString(), - + /** * Do not display preview overlay on screen */ '--nopreview', /** - * RAW (Save Bayer Data) - */ + * RAW (Save Bayer Data) + * This option inserts the raw Bayer data from the camera in to the + * JPEG metadata. + */ ...(this.options.raw ? ['--raw'] : []), - + /** * JPEG Quality + * Quality 100 is almost completely uncompressed. 75 is a good allround value. */ ...(this.options.quality ? ['--quality', this.options.quality.toString()] : []), + /** + * Burst + * This prevents the camera from returning to preview mode in between captures, + * meaning that captures can be taken closer together. + */ + ...(this.options.burst ? ['--burst'] : []), + + /** + * Thumbnail Settings (x:y:quality) + * Allows specification of the thumbnail image inserted in to the JPEG file. + * If not specified, defaults are a size of 64x48 at quality 35. + */ + ...(this.options.thumbnail + ? [ + '--thumb', + Array.isArray(this.options.thumbnail) + ? this.options.thumbnail.join(':') + : this.options.thumbnail, + ] + : []), + /** * Output to stdout */ diff --git a/src/lib/stream-camera.ts b/src/lib/stream-camera.ts index 841d306..b584b31 100644 --- a/src/lib/stream-camera.ts +++ b/src/lib/stream-camera.ts @@ -1,7 +1,16 @@ import { ChildProcessWithoutNullStreams, spawn } from 'child_process'; import { EventEmitter } from 'events'; import * as stream from 'stream'; -import { AwbMode, DynamicRange, ExposureMode, Flip, ImxfxMode, Rotation } from '..'; +import { + AwbMode, + DynamicRange, + ExposureMode, + FlickerMode, + Flip, + ImxfxMode, + MeteringMode, + Rotation, +} from '..'; import { getSharedArgs } from './shared-args'; export enum Codec { @@ -38,12 +47,17 @@ export interface StreamOptions { exposureCompensation?: number; exposureMode?: ExposureMode; awbMode?: AwbMode; + awbGains?: [number, number]; analogGain?: number; digitalGain?: number; imageEffect?: ImxfxMode; colourEffect?: [number, number]; // U,V dynamicRange?: DynamicRange; videoStabilisation?: boolean; + statistics?: boolean; + meteringMode?: MeteringMode; + flickerMode?: FlickerMode; + roi?: [number, number, number, number]; // X, Y, W, H } declare interface StreamCamera { @@ -130,7 +144,22 @@ class StreamCamera extends EventEmitter { * | 4 | 1640x1232 | 4:3 | 0.1-40fps | Full | 2x2 | * | 5 | 1640x922 | 16:9 | 0.1-40fps | Full | 2x2 | * | 6 | 1280x720 | 16:9 | 40-90fps | Partial | 2x2 | - * | 7 | 640x480 | 4:3 | 40-90fps | Partial | 2x2 | + * | 7 | 640x480 | 4:3 | 40-200fps* | Partial | 2x2 | + * + * *For frame rates over 120fps, it is necessary to turn off automatic exposure and gain + * control using -ex off. Doing so should achieve the higher frame rates, but exposure + * time and gains will need to be set to fixed values supplied by the user. + * + * + * HQ Camera (IMX477): + * + * | Mode | Size | Aspect Ratio | Frame rates | FOV | Binning | + * |------|---------------------|--------------|-------------|---------|-------------| + * | 0 | automatic selection | | | | | + * | 1 | 2028x1080 | 169:90 | 0.1-50fps | Partial | 2x2 binned | + * | 2 | 2028x1520 | 4:3 | 0.1-50fps | Full | 2x2 binned | + * | 3 | 4056x3040 | 4:3 | 0.005-10fps | Full | None | + * | 4 | 1332x990 | 74:55 | 50.1-120fps | Partial | 2x2 binned | * */ ...(this.options.sensorMode ? ['--mode', this.options.sensorMode.toString()] : []), @@ -230,7 +259,7 @@ class StreamCamera extends EventEmitter { createStream() { const newStream = new stream.Readable({ - read: () => { }, + read: () => {}, }); this.streams.push(newStream); From 8965a83184a277307ad1f6a510b657768aed9268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gast=C3=B3n=20Zalba?= Date: Tue, 21 Feb 2023 15:33:33 -0300 Subject: [PATCH 4/9] Fix roi argument --- src/lib/shared-args.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/shared-args.ts b/src/lib/shared-args.ts index 6bb0621..0a57c2c 100644 --- a/src/lib/shared-args.ts +++ b/src/lib/shared-args.ts @@ -164,6 +164,6 @@ export function getSharedArgs(options: StillOptions | StreamOptions): string[] { * the top left corner, and a width and height, all values in * normalised coordinates (0.0-1.0). */ - ...(options.roi ? ['--roi', options.toString()] : []), + ...(options.roi ? ['--roi', options.roi.toString()] : []), ]; } From 5ad5604e6738e1d251e6e3cf95cc984124f5a1d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gast=C3=B3n=20Zalba?= Date: Wed, 22 Feb 2023 20:13:48 -0300 Subject: [PATCH 5/9] Requested changes applied --- README.md | 62 ++++++++++++++++++++-------------------- src/index.ts | 6 ++-- src/lib/shared-args.ts | 6 ++-- src/lib/still-camera.ts | 8 +++--- src/lib/stream-camera.ts | 8 +++--- 5 files changed, 45 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index f421f60..c640849 100644 --- a/README.md +++ b/README.md @@ -267,10 +267,10 @@ const stillCamera = new StillCamera({ - `analogGain: number` - _Default: `0`_ - `digitalGain: number` - _Default: `0`_ - `quality: number` - _Default: `100`_ -- `colourEffect: [number, number]` - _Default: `[0,0]`_ -- [`imageEffect: ImxfxMode`](#imageeffect) - _Default: `ImxfxMode.None`_ +- `colorEffect: [number, number]` - _Default: `[0,0]`_ +- [`imageEffect: ImageEffectMode`](#imageeffect) - _Default: `ImageEffectMode.None`_ - [`dynamicRange: DynamicRange`](#dynamicrange) - _Default: `DynamicRange.Off`_ -- `videoStabilisation: boolean` - _Default: `false`_ +- `videoStabilization: boolean` - _Default: `false`_ - `raw: boolean` - _Default: `false`_ - [`meteringMode`](#meteringMode) - _Default: `MeteringMode.Off`_ - `thumbnail: [number, number, number] | 'none'` - _Default: `[64, 48, 35]`_ @@ -325,13 +325,13 @@ const streamCamera = new StreamCamera({ - `awbGains: [number, number]` - _Default: `null`_ - `analogGain: number` - _Default: `0`_ - `digitalGain: number` - _Default: `0`_ -- `colourEffect: [number, number]` - _Default: `[0,0]`_ -- [`imageEffect: ImxfxMode`](#imageeffect) - _Default: `ImxfxMode.None`_ +- `colorEffect: [number, number]` - _Default: `[0,0]`_ +- [`imageEffect: ImageEffectMode`](#imageeffect) - _Default: `ImageEffectMode.None`_ - [`dynamicRange: DynamicRange`](#dynamicrange) - _Default: `DynamicRange.Off`_ -- `videoStabilisation: boolean` - _Default: `false`_ +- `videoStabilization: boolean` - _Default: `false`_ - [`meteringMode`](#meteringMode) - _Default: `MeteringMode.Off`_ -- [`flickerMode`](#flickerMode) - _Default: `null`_ -- `roi: [number, number, number, number]` - _Default: `null`_ +- [`flickerMode`](#flickerMode) - _Default: `FlickerMode.Off`_ +- `roi: [number, number, number, number]` - _Default: Full sensor_ - `statistics: boolean` - _Default: `false`_ ### `startCapture(): Promise` @@ -530,29 +530,29 @@ import { AwbMode } from 'pi-camera-connect'; Image Effect options. -- `ImxfxMode.None` -- `ImxfxMode.Negative` -- `ImxfxMode.Solarise` -- `ImxfxMode.Sketch` -- `ImxfxMode.Denoise` -- `ImxfxMode.Emboss` -- `ImxfxMode.OilPaint` -- `ImxfxMode.Hatch` -- `ImxfxMode.GPen` -- `ImxfxMode.Pastel` -- `ImxfxMode.Watercolour` -- `ImxfxMode.Film` -- `ImxfxMode.Blur` -- `ImxfxMode.Saturation` -- `ImxfxMode.ColourSwap` -- `ImxfxMode.WashedOut` -- `ImxfxMode.Posterise` -- `ImxfxMode.ColourPoint` -- `ImxfxMode.ColourBalance` -- `ImxfxMode.Cartoon` +- `ImageEffectMode.None` +- `ImageEffectMode.Negative` +- `ImageEffectMode.Solarise` +- `ImageEffectMode.Sketch` +- `ImageEffectMode.Denoise` +- `ImageEffectMode.Emboss` +- `ImageEffectMode.OilPaint` +- `ImageEffectMode.Hatch` +- `ImageEffectMode.GPen` +- `ImageEffectMode.Pastel` +- `ImageEffectMode.Watercolour` +- `ImageEffectMode.Film` +- `ImageEffectMode.Blur` +- `ImageEffectMode.Saturation` +- `ImageEffectMode.ColourSwap` +- `ImageEffectMode.WashedOut` +- `ImageEffectMode.Posterise` +- `ImageEffectMode.ColourPoint` +- `ImageEffectMode.ColourBalance` +- `ImageEffectMode.Cartoon` ```javascript -import { ImxfxMode } from 'pi-camera-connect'; +import { ImageEffectMode } from 'pi-camera-connect'; ``` ## `DynamicRange` @@ -587,8 +587,8 @@ Dynamic Range options. - `FlickerMode.Off` - `FlickerMode.Auto` -- `FlickerMode.50hz` -- `FlickerMode.60hz` +- `FlickerMode.Frq50hz` +- `FlickerMode.Frq60hz` ```javascript import { FlickerMode } from 'pi-camera-connect'; diff --git a/src/index.ts b/src/index.ts index c5486ce..e3840ea 100644 --- a/src/index.ts +++ b/src/index.ts @@ -45,7 +45,7 @@ export enum AwbMode { GreyWorld = 'greyworld', } -export enum ImxfxMode { +export enum ImageEffectMode { None = 'none', Negative = 'negative', Solarise = 'solarise', @@ -85,6 +85,6 @@ export enum MeteringMode { export enum FlickerMode { Off = 'off', Auto = 'auto', - '50hz' = '50hz', - '60Hz' = '60hz', + 'Frq50hz' = '50hz', + 'Frq60Hz' = '60hz', } diff --git a/src/lib/shared-args.ts b/src/lib/shared-args.ts index 0a57c2c..5c73c28 100644 --- a/src/lib/shared-args.ts +++ b/src/lib/shared-args.ts @@ -117,12 +117,12 @@ export function getSharedArgs(options: StillOptions | StreamOptions): string[] { ...(options.dynamicRange ? ['--drc', options.dynamicRange] : []), /** - * Colour Effects + * Color Effects * The supplied U and V parameters (range 0 to 255) are applied to * the U and Y channels of the image. For example, --colfx 128:128 * should result in a monochrome image. */ - ...(options.colourEffect ? ['--colfx', options.colourEffect.join(':')] : []), + ...(options.colorEffect ? ['--colfx', options.colorEffect.join(':')] : []), /** * Metering @@ -147,7 +147,7 @@ export function getSharedArgs(options: StillOptions | StreamOptions): string[] { * Video Stabilisation * In video mode only, turn on video stabilization. */ - ...(options.videoStabilisation ? ['--vstab'] : []), + ...(options.videoStabilization ? ['--vstab'] : []), /** * Statistics diff --git a/src/lib/still-camera.ts b/src/lib/still-camera.ts index 44100a1..dbd5a04 100644 --- a/src/lib/still-camera.ts +++ b/src/lib/still-camera.ts @@ -4,7 +4,7 @@ import { ExposureMode, FlickerMode, Flip, - ImxfxMode, + ImageEffectMode, MeteringMode, Rotation, } from '..'; @@ -29,10 +29,10 @@ export interface StillOptions { awbGains?: [number, number]; analogGain?: number; digitalGain?: number; - imageEffect?: ImxfxMode; - colourEffect?: [number, number]; // U,V + imageEffect?: ImageEffectMode; + colorEffect?: [number, number]; // U,V dynamicRange?: DynamicRange; - videoStabilisation?: boolean; + videoStabilization?: boolean; raw?: boolean; quality?: number; statistics?: boolean; diff --git a/src/lib/stream-camera.ts b/src/lib/stream-camera.ts index b584b31..98822db 100644 --- a/src/lib/stream-camera.ts +++ b/src/lib/stream-camera.ts @@ -7,7 +7,7 @@ import { ExposureMode, FlickerMode, Flip, - ImxfxMode, + ImageEffectMode, MeteringMode, Rotation, } from '..'; @@ -50,10 +50,10 @@ export interface StreamOptions { awbGains?: [number, number]; analogGain?: number; digitalGain?: number; - imageEffect?: ImxfxMode; - colourEffect?: [number, number]; // U,V + imageEffect?: ImageEffectMode; + colorEffect?: [number, number]; // U,V dynamicRange?: DynamicRange; - videoStabilisation?: boolean; + videoStabilization?: boolean; statistics?: boolean; meteringMode?: MeteringMode; flickerMode?: FlickerMode; From 71447e6153d98a735b1a7be26608d46023475178 Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Wed, 22 Feb 2023 17:07:26 -0700 Subject: [PATCH 6/9] chore: stabilization comment spelling --- src/lib/shared-args.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/shared-args.ts b/src/lib/shared-args.ts index 5c73c28..2f45702 100644 --- a/src/lib/shared-args.ts +++ b/src/lib/shared-args.ts @@ -144,7 +144,7 @@ export function getSharedArgs(options: StillOptions | StreamOptions): string[] { ...(options.flickerMode ? ['--flicker', options.flickerMode] : []), /** - * Video Stabilisation + * Video Stabilization * In video mode only, turn on video stabilization. */ ...(options.videoStabilization ? ['--vstab'] : []), From 2032cfb1d990d8a524d719e61e9926f1344c4b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gast=C3=B3n=20Zalba?= Date: Sun, 26 Feb 2023 13:49:18 -0300 Subject: [PATCH 7/9] Added annotate and exif. Improved readme --- README.md | 40 +++++++++++++++++++--------------- src/index.ts | 4 ++-- src/lib/shared-args.ts | 15 ++++++++++++- src/lib/still-camera.test.ts | 19 +++++++++++++++- src/lib/still-camera.ts | 42 +++++++++++++++++++++++++++--------- src/lib/stream-camera.ts | 4 +++- 6 files changed, 92 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index c640849..f340249 100644 --- a/README.md +++ b/README.md @@ -231,7 +231,7 @@ Note that this example produces a raw H264 video. Wrapping it in a video contain - [`ExposureMode`](#exposuremode) - [`AwbMode`](#awbmode) - [`DynamicRange`](#dynamicRange) -- [`ImageEffect`](#imageEffect) +- [`ImageEffectMode`](#imageEffectMode) ## `StillCamera` @@ -263,21 +263,25 @@ const stillCamera = new StillCamera({ - `exposureCompensation: number` - _Range: `-10`-`10`; Default: `0`_ - [`exposureMode: ExposureMode`](#exposuremode) - _Default: `ExposureMode.Auto`_ - [`awbMode: AwbMode`](#awbmode) - _Default: `AwbMode.Auto`_ -- `awbGains: [number, number]` - _Default: `null`_ -- `analogGain: number` - _Default: `0`_ -- `digitalGain: number` - _Default: `0`_ -- `quality: number` - _Default: `100`_ -- `colorEffect: [number, number]` - _Default: `[0,0]`_ -- [`imageEffect: ImageEffectMode`](#imageeffect) - _Default: `ImageEffectMode.None`_ +- `awbGains: [number, number]` - _Default: `undefined`_ +- `analogGain: number` - _Range: `1.0`-`12.0` (OV5647: `1.0`-`0.8`); Default: `0`_ +- `digitalGain: number` - _Range: `1.0`-`64.0`; efault: `0`_ +- `quality: number` - _Range:`1`-`100`; Default: `100`_ +- `colorEffect: [number, number]` (U, V) - _Range: `0-255`; _Default: `undefined`_ +- [`imageEffectMode: ImageEffectMode`](#imageeffectmode) - _Default: `ImageEffectMode.None`_ - [`dynamicRange: DynamicRange`](#dynamicrange) - _Default: `DynamicRange.Off`_ - `videoStabilization: boolean` - _Default: `false`_ - `raw: boolean` - _Default: `false`_ - [`meteringMode`](#meteringMode) - _Default: `MeteringMode.Off`_ -- `thumbnail: [number, number, number] | 'none'` - _Default: `[64, 48, 35]`_ -- [`flickerMode`](#flickerMode) - _Default: `null`_ +- `thumbnail: [number, number, number] | false` (X, Y, Q) - _Default: `[64, 48, 35]`; `false` to remove thumbnail_ +- [`flickerMode`](#flickerMode) - _Default: `FlickerMode.Off`_ - `burst: boolean` - _Default: `false`_ -- `roi: [number, number, number, number]` - _Default: `null`_ +- `roi: [number, number, number, number]` (X, Y, W, H) - _Range: `0.0`-`1.0`; _Default: `[0, 0, 1, 1]` (Full sensor)_ - `statistics: boolean` - _Default: `false`_ +- `exif: { [key:string]: string | number } | false` - _Default: Automatic camera values; `false` to remove default exif_ +- `gpsExif: boolean` - _Default: `false`_ +- `annotate: (number | string)[]` - _Default: No annotations_ +- `annotateExtra: [number, string, string]` (fontSize, fontColor, backgroundColor) - _Default: [32, '0xff', '0x808000']_ ### `StillCamera.takeImage(): Promise` @@ -322,17 +326,19 @@ const streamCamera = new StreamCamera({ - `exposureCompensation: number` - _Range: `-10`-`10`; Default: `0`_ - [`exposureMode: ExposureMode`](#exposuremode) - _Default: `ExposureMode.Auto`_ - [`awbMode: AwbMode`](#awbmode) - _Default: `AwbMode.Auto`_ -- `awbGains: [number, number]` - _Default: `null`_ -- `analogGain: number` - _Default: `0`_ -- `digitalGain: number` - _Default: `0`_ -- `colorEffect: [number, number]` - _Default: `[0,0]`_ -- [`imageEffect: ImageEffectMode`](#imageeffect) - _Default: `ImageEffectMode.None`_ +- `awbGains: [number, number]` - _Default: `undefined`_ +- `analogGain: number` - _Range: `1.0`-`12.0` (OV5647: `1.0`-`0.8`); Default: `0`_ +- `digitalGain: number` - _Range: `1.0`-`64.0`; efault: `0`_ +- `colorEffect: [number, number]` (U, V) - _Range: `0-255`; _Default: `undefined`_ +- [`imageEffectMode: ImageEffectMode`](#imageeffectmode) - _Default: `ImageEffectMode.None`_ - [`dynamicRange: DynamicRange`](#dynamicrange) - _Default: `DynamicRange.Off`_ - `videoStabilization: boolean` - _Default: `false`_ - [`meteringMode`](#meteringMode) - _Default: `MeteringMode.Off`_ - [`flickerMode`](#flickerMode) - _Default: `FlickerMode.Off`_ -- `roi: [number, number, number, number]` - _Default: Full sensor_ +- `roi: [number, number, number, number]` (X, Y, W, H) - _Range: `0.0`-`1.0`; Default: `[0, 0, 1, 1]` (Full sensor)_ - `statistics: boolean` - _Default: `false`_ +- `annotate: (number | string)[]` - _Default: No annotations_ +- `annotateExtra: [number, string, string]` (fontSize, fontColor, backgroundColor) - _Default: [32, '0xff', '0x808000']_ ### `startCapture(): Promise` @@ -526,7 +532,7 @@ White balance mode options. import { AwbMode } from 'pi-camera-connect'; ``` -## `ImageEffect` +## `ImageEffectMode` Image Effect options. diff --git a/src/index.ts b/src/index.ts index e3840ea..cd0c31b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -85,6 +85,6 @@ export enum MeteringMode { export enum FlickerMode { Off = 'off', Auto = 'auto', - 'Frq50hz' = '50hz', - 'Frq60Hz' = '60hz', + Frq50hz = '50hz', + Frq60Hz = '60hz', } diff --git a/src/lib/shared-args.ts b/src/lib/shared-args.ts index 5c73c28..ba8323f 100644 --- a/src/lib/shared-args.ts +++ b/src/lib/shared-args.ts @@ -109,7 +109,7 @@ export function getSharedArgs(options: StillOptions | StreamOptions): string[] { /** * Image Effect */ - ...(options.imageEffect ? ['--imxfx', options.imageEffect.toString()] : []), + ...(options.imageEffectMode ? ['--imxfx', options.imageEffectMode.toString()] : []), /** * Dynamic Range Control @@ -165,5 +165,18 @@ export function getSharedArgs(options: StillOptions | StreamOptions): string[] { * normalised coordinates (0.0-1.0). */ ...(options.roi ? ['--roi', options.roi.toString()] : []), + + /** + * Annotate + * Adds some text and/or metadata to the picture. + */ + ...(options.annotate ? options.annotate.flatMap(e => ['--annotate', e.toString()]) : []), + + /** + * Annotate extra + * Specifies annotation size, text colour, and background color. + * Colors are in hex YUV format. Size ranges from 6 - 160; default is 32 + */ + ...(options.annotateExtra ? ['--annotateex', options.annotateExtra.toString()] : []), ]; } diff --git a/src/lib/still-camera.test.ts b/src/lib/still-camera.test.ts index c300fc4..a71d227 100644 --- a/src/lib/still-camera.test.ts +++ b/src/lib/still-camera.test.ts @@ -1,5 +1,6 @@ import * as fs from 'fs'; import { performance } from 'perf_hooks'; +import { ImageEffectMode } from '..'; import StillCamera from './still-camera'; @@ -12,7 +13,23 @@ if (!fs.existsSync(TEST_IMAGES_DIR)) { test('takeImage() returns JPEG', async () => { const t0 = performance.now(); - const stillCamera = new StillCamera(); + const stillCamera = new StillCamera({ + imageEffectMode: ImageEffectMode.Sketch, + + // 2X zoom + roi: [0.25, 0.25, 0.5, 0.5], + + // Size 50 black text on white background + annotateExtra: [50, '0x00', '0x8080FF'], + + // Custom text and Date/Time + annotate: [4, 'pi-camera-connect %Y-%m-%d %X'], + + exif: { + 'IFD0.Artist': 'pi-camera-connect', + 'IFD0.ImageDescription': 'This is a custom description', + }, + }); const jpegImage = await stillCamera.takeImage(); const t1 = performance.now(); diff --git a/src/lib/still-camera.ts b/src/lib/still-camera.ts index dbd5a04..021c5d0 100644 --- a/src/lib/still-camera.ts +++ b/src/lib/still-camera.ts @@ -29,18 +29,22 @@ export interface StillOptions { awbGains?: [number, number]; analogGain?: number; digitalGain?: number; - imageEffect?: ImageEffectMode; + imageEffectMode?: ImageEffectMode; colorEffect?: [number, number]; // U,V dynamicRange?: DynamicRange; videoStabilization?: boolean; raw?: boolean; quality?: number; statistics?: boolean; - thumbnail?: [number, number, number] | 'none'; // X, Y, Q + thumbnail?: [number, number, number] | false; // X, Y, Q meteringMode?: MeteringMode; flickerMode?: FlickerMode; burst?: boolean; roi?: [number, number, number, number]; // X, Y, W, H + exif?: { [key: string]: string | number } | false; + gpsExif?: boolean; + annotate?: (number | string)[]; + annotateExtra?: [number, string, string]; // fontSize, fontColor, backgroundColor } export default class StillCamera { @@ -100,16 +104,34 @@ export default class StillCamera { * Thumbnail Settings (x:y:quality) * Allows specification of the thumbnail image inserted in to the JPEG file. * If not specified, defaults are a size of 64x48 at quality 35. + * `false` will remove the default thumbnail */ - ...(this.options.thumbnail - ? [ - '--thumb', - Array.isArray(this.options.thumbnail) - ? this.options.thumbnail.join(':') - : this.options.thumbnail, - ] + ...(Array.isArray(this.options.thumbnail) || this.options.thumbnail === false + ? ['--thumb', !this.options.thumbnail ? 'none' : this.options.thumbnail.join(':')] : []), + /** + * Exif information + * Allows the insertion of specific EXIF tags into the JPEG image. + * You can have up to 32 EXIF tag entries. + * Will overwrite any EXIF tag set automatically by the camera. + */ + ...(this.options.exif + ? Object.keys(this.options.exif).flatMap( + key => + ['--exif', `${key}=${(this.options.exif as any)[key as keyof StillOptions['exif']]}`], + ) + : []), + // `false` will remove all the default EXIF information + ...(this.options.exif === false ? ['--exif', 'none'] : []), + + /** + * GPS Exif + * Applies real-time EXIF information from any attached GPS dongle (using GSPD) to the image + * (requires libgps.so to be installed) + */ + ...(this.options.gpsExif ? ['--gpsexif'] : []), + /** * Output to stdout */ @@ -117,7 +139,7 @@ export default class StillCamera { '-', ]); } catch (err) { - if (err.code === 'ENOENT') { + if ((err as NodeJS.ErrnoException).code === 'ENOENT') { throw new Error( "Could not take image with StillCamera. Are you running on a Raspberry Pi with 'raspistill' installed?", ); diff --git a/src/lib/stream-camera.ts b/src/lib/stream-camera.ts index 98822db..848e27c 100644 --- a/src/lib/stream-camera.ts +++ b/src/lib/stream-camera.ts @@ -50,7 +50,7 @@ export interface StreamOptions { awbGains?: [number, number]; analogGain?: number; digitalGain?: number; - imageEffect?: ImageEffectMode; + imageEffectMode?: ImageEffectMode; colorEffect?: [number, number]; // U,V dynamicRange?: DynamicRange; videoStabilization?: boolean; @@ -58,6 +58,8 @@ export interface StreamOptions { meteringMode?: MeteringMode; flickerMode?: FlickerMode; roi?: [number, number, number, number]; // X, Y, W, H + annotate?: (number | string)[]; + annotateExtra?: [number, string, string]; // fontSize, fontColor, backgroundColor } declare interface StreamCamera { From 59de59282097e0aabbc2f6efc8317052ea20219e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gast=C3=B3n=20Zalba?= Date: Sun, 26 Feb 2023 18:12:14 -0300 Subject: [PATCH 8/9] README details and format --- README.md | 30 +++++++++++++++--------------- src/lib/still-camera.ts | 8 ++++---- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index f340249..8c0a793 100644 --- a/README.md +++ b/README.md @@ -263,25 +263,25 @@ const stillCamera = new StillCamera({ - `exposureCompensation: number` - _Range: `-10`-`10`; Default: `0`_ - [`exposureMode: ExposureMode`](#exposuremode) - _Default: `ExposureMode.Auto`_ - [`awbMode: AwbMode`](#awbmode) - _Default: `AwbMode.Auto`_ -- `awbGains: [number, number]` - _Default: `undefined`_ -- `analogGain: number` - _Range: `1.0`-`12.0` (OV5647: `1.0`-`0.8`); Default: `0`_ -- `digitalGain: number` - _Range: `1.0`-`64.0`; efault: `0`_ -- `quality: number` - _Range:`1`-`100`; Default: `100`_ -- `colorEffect: [number, number]` (U, V) - _Range: `0-255`; _Default: `undefined`_ +- `awbGains: [number, number]` - _Range: `0.0`-`8.0`; Default: `undefined`_ +- `analogGain: number` - _Range: `1.0`-`12.0` (OV5647: `1.0`-`8.0`); Default: `0`_ +- `digitalGain: number` - _Range: `1.0`-`64.0`; Default: `0`_ +- `quality: number` - _Range: `0`-`100`; Default: `100`_ +- `colorEffect: [number, number]` (U, V) - _Range: `0-255`; Default: `undefined`_ - [`imageEffectMode: ImageEffectMode`](#imageeffectmode) - _Default: `ImageEffectMode.None`_ - [`dynamicRange: DynamicRange`](#dynamicrange) - _Default: `DynamicRange.Off`_ - `videoStabilization: boolean` - _Default: `false`_ - `raw: boolean` - _Default: `false`_ - [`meteringMode`](#meteringMode) - _Default: `MeteringMode.Off`_ -- `thumbnail: [number, number, number] | false` (X, Y, Q) - _Default: `[64, 48, 35]`; `false` to remove thumbnail_ +- `thumbnail: [number, number, number] | false` (X, Y, Q) - _Default: `[64, 48, 35]`; `false` to dismiss thumbnail_ - [`flickerMode`](#flickerMode) - _Default: `FlickerMode.Off`_ - `burst: boolean` - _Default: `false`_ -- `roi: [number, number, number, number]` (X, Y, W, H) - _Range: `0.0`-`1.0`; _Default: `[0, 0, 1, 1]` (Full sensor)_ +- `roi: [number, number, number, number]` (X, Y, W, H) - _Range: `0.0`-`1.0`; Default: `[0, 0, 1, 1]` (Full sensor)_ - `statistics: boolean` - _Default: `false`_ -- `exif: { [key:string]: string | number } | false` - _Default: Automatic camera values; `false` to remove default exif_ +- `exif: { [key:string]: string | number } | false` - _Default: Default camera values; `false` to dissmis default exif_ - `gpsExif: boolean` - _Default: `false`_ - `annotate: (number | string)[]` - _Default: No annotations_ -- `annotateExtra: [number, string, string]` (fontSize, fontColor, backgroundColor) - _Default: [32, '0xff', '0x808000']_ +- `annotateExtra: [number, string, string]` (fontSize, fontColor, backgroundColor) - _Default: `[32, '0xff', '0x808000']`_ ### `StillCamera.takeImage(): Promise` @@ -326,19 +326,19 @@ const streamCamera = new StreamCamera({ - `exposureCompensation: number` - _Range: `-10`-`10`; Default: `0`_ - [`exposureMode: ExposureMode`](#exposuremode) - _Default: `ExposureMode.Auto`_ - [`awbMode: AwbMode`](#awbmode) - _Default: `AwbMode.Auto`_ -- `awbGains: [number, number]` - _Default: `undefined`_ -- `analogGain: number` - _Range: `1.0`-`12.0` (OV5647: `1.0`-`0.8`); Default: `0`_ -- `digitalGain: number` - _Range: `1.0`-`64.0`; efault: `0`_ -- `colorEffect: [number, number]` (U, V) - _Range: `0-255`; _Default: `undefined`_ +- `awbGains: [number, number]` - _Range: `0.0`-`8.0`; Default: `undefined`_ +- `analogGain: number` - _Range: `1.0`-`12.0` (OV5647: `1.0`-`8.0`); Default: `0`_ +- `digitalGain: number` - _Range: `1.0`-`64.0`; Default: `0`_ +- `colorEffect: [number, number]` (U, V) - _Range: `0-255`; Default: `undefined`_ - [`imageEffectMode: ImageEffectMode`](#imageeffectmode) - _Default: `ImageEffectMode.None`_ - [`dynamicRange: DynamicRange`](#dynamicrange) - _Default: `DynamicRange.Off`_ - `videoStabilization: boolean` - _Default: `false`_ - [`meteringMode`](#meteringMode) - _Default: `MeteringMode.Off`_ - [`flickerMode`](#flickerMode) - _Default: `FlickerMode.Off`_ -- `roi: [number, number, number, number]` (X, Y, W, H) - _Range: `0.0`-`1.0`; Default: `[0, 0, 1, 1]` (Full sensor)_ +- `roi: [number, number, number, number]` (X, Y, W, H) - _Range: `0.0`-`1.0`; Default: `[0, 0, 1, 1]` (Full sensor)_ - `statistics: boolean` - _Default: `false`_ - `annotate: (number | string)[]` - _Default: No annotations_ -- `annotateExtra: [number, string, string]` (fontSize, fontColor, backgroundColor) - _Default: [32, '0xff', '0x808000']_ +- `annotateExtra: [number, string, string]` (fontSize, fontColor, backgroundColor) - _Default: `[32, '0xff', '0x808000']`_ ### `startCapture(): Promise` diff --git a/src/lib/still-camera.ts b/src/lib/still-camera.ts index 021c5d0..77ed62b 100644 --- a/src/lib/still-camera.ts +++ b/src/lib/still-camera.ts @@ -117,10 +117,10 @@ export default class StillCamera { * Will overwrite any EXIF tag set automatically by the camera. */ ...(this.options.exif - ? Object.keys(this.options.exif).flatMap( - key => - ['--exif', `${key}=${(this.options.exif as any)[key as keyof StillOptions['exif']]}`], - ) + ? Object.keys(this.options.exif).flatMap(key => [ + '--exif', + `${key}=${(this.options.exif as any)[key as keyof StillOptions['exif']]}`, + ]) : []), // `false` will remove all the default EXIF information ...(this.options.exif === false ? ['--exif', 'none'] : []), From 648335896610d99438dc7e28c5a9c63e65f30102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gast=C3=B3n=20Zalba?= Date: Tue, 28 Feb 2023 17:07:37 -0300 Subject: [PATCH 9/9] Fix uppercase in FlickerMode enum --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index cd0c31b..58ddf71 100644 --- a/src/index.ts +++ b/src/index.ts @@ -86,5 +86,5 @@ export enum FlickerMode { Off = 'off', Auto = 'auto', Frq50hz = '50hz', - Frq60Hz = '60hz', + Frq60hz = '60hz', }