tethr
Version:
Controlls USB-connected cameras, webcam, and smartphone camera from browser
781 lines • 31.5 kB
JavaScript
import { BiMap } from 'bim';
import { times } from 'lodash';
import { CanvasMediaStream } from '../CanvasMediaStream';
import { ObjectFormatCode, ResCode } from '../PTPDatacode';
import { PTPDataView } from '../PTPDataView';
import { isntNil, readonlyConfigDesc } from '../util';
import { TethrPTPUSB } from './TethrPTPUSB';
var OpCodePanasonic;
(function (OpCodePanasonic) {
OpCodePanasonic[OpCodePanasonic["OpenSession"] = 37122] = "OpenSession";
OpCodePanasonic[OpCodePanasonic["CloseSession"] = 37123] = "CloseSession";
OpCodePanasonic[OpCodePanasonic["GetDevicePropDesc"] = 37128] = "GetDevicePropDesc";
OpCodePanasonic[OpCodePanasonic["GetDevicePropValue"] = 37890] = "GetDevicePropValue";
OpCodePanasonic[OpCodePanasonic["SetDevicePropValue"] = 37891] = "SetDevicePropValue";
OpCodePanasonic[OpCodePanasonic["InitiateCapture"] = 37892] = "InitiateCapture";
OpCodePanasonic[OpCodePanasonic["CtrlLiveview"] = 37893] = "CtrlLiveview";
OpCodePanasonic[OpCodePanasonic["Liveview"] = 37906] = "Liveview";
OpCodePanasonic[OpCodePanasonic["GetLiveviewSettings"] = 37908] = "GetLiveviewSettings";
OpCodePanasonic[OpCodePanasonic["SetLiveviewSettings"] = 37909] = "SetLiveviewSettings";
OpCodePanasonic[OpCodePanasonic["ManualFocusDrive"] = 37910] = "ManualFocusDrive";
OpCodePanasonic[OpCodePanasonic["LiveviewImage"] = 38662] = "LiveviewImage";
})(OpCodePanasonic || (OpCodePanasonic = {}));
var EventCodePanasonic;
(function (EventCodePanasonic) {
EventCodePanasonic[EventCodePanasonic["DevicePropChanged"] = 49410] = "DevicePropChanged";
EventCodePanasonic[EventCodePanasonic["ObjectAdded"] = 49416] = "ObjectAdded";
})(EventCodePanasonic || (EventCodePanasonic = {}));
// Panasonic does not have regular device properties, they use some 32bit values
var DevicePropCodePanasonic;
(function (DevicePropCodePanasonic) {
DevicePropCodePanasonic[DevicePropCodePanasonic["PhotoStyle"] = 33554448] = "PhotoStyle";
DevicePropCodePanasonic[DevicePropCodePanasonic["PhotoStyle_Param"] = 33554449] = "PhotoStyle_Param";
DevicePropCodePanasonic[DevicePropCodePanasonic["ISO"] = 33554464] = "ISO";
DevicePropCodePanasonic[DevicePropCodePanasonic["ISO_Param"] = 33554465] = "ISO_Param";
DevicePropCodePanasonic[DevicePropCodePanasonic["ISO_UpperLimit"] = 33554466] = "ISO_UpperLimit";
DevicePropCodePanasonic[DevicePropCodePanasonic["ShutterSpeed"] = 33554480] = "ShutterSpeed";
DevicePropCodePanasonic[DevicePropCodePanasonic["ShutterSpeed_Param"] = 33554481] = "ShutterSpeed_Param";
DevicePropCodePanasonic[DevicePropCodePanasonic["ShutterSpeed_RangeLimit"] = 33554482] = "ShutterSpeed_RangeLimit";
DevicePropCodePanasonic[DevicePropCodePanasonic["Aperture"] = 33554496] = "Aperture";
DevicePropCodePanasonic[DevicePropCodePanasonic["Aperture_Param"] = 33554497] = "Aperture_Param";
DevicePropCodePanasonic[DevicePropCodePanasonic["Aperture_RangeLimit"] = 33554498] = "Aperture_RangeLimit";
DevicePropCodePanasonic[DevicePropCodePanasonic["WhiteBalance"] = 33554512] = "WhiteBalance";
DevicePropCodePanasonic[DevicePropCodePanasonic["WhiteBalance_Param"] = 33554513] = "WhiteBalance_Param";
DevicePropCodePanasonic[DevicePropCodePanasonic["WhiteBalance_KSet"] = 33554514] = "WhiteBalance_KSet";
DevicePropCodePanasonic[DevicePropCodePanasonic["WhiteBalance_ADJ_AB"] = 33554515] = "WhiteBalance_ADJ_AB";
DevicePropCodePanasonic[DevicePropCodePanasonic["WhiteBalance_ADJ_GM"] = 33554516] = "WhiteBalance_ADJ_GM";
DevicePropCodePanasonic[DevicePropCodePanasonic["WhiteBalance_ADJ_AB_Sep"] = 33554517] = "WhiteBalance_ADJ_AB_Sep";
DevicePropCodePanasonic[DevicePropCodePanasonic["Exposure"] = 33554528] = "Exposure";
DevicePropCodePanasonic[DevicePropCodePanasonic["Exposure_Param"] = 33554529] = "Exposure_Param";
DevicePropCodePanasonic[DevicePropCodePanasonic["Exposure_RangeLimit"] = 33554530] = "Exposure_RangeLimit";
DevicePropCodePanasonic[DevicePropCodePanasonic["AFArea"] = 33554544] = "AFArea";
DevicePropCodePanasonic[DevicePropCodePanasonic["AFArea_AFModeParam"] = 33554545] = "AFArea_AFModeParam";
DevicePropCodePanasonic[DevicePropCodePanasonic["AFArea_AFAreaParam"] = 33554546] = "AFArea_AFAreaParam";
DevicePropCodePanasonic[DevicePropCodePanasonic["AFArea_SetQuickAFParam"] = 33554547] = "AFArea_SetQuickAFParam";
DevicePropCodePanasonic[DevicePropCodePanasonic["CameraMode"] = 33554560] = "CameraMode";
DevicePropCodePanasonic[DevicePropCodePanasonic["CameraMode_DriveMode"] = 33554561] = "CameraMode_DriveMode";
DevicePropCodePanasonic[DevicePropCodePanasonic["CameraMode_ModePos"] = 33554562] = "CameraMode_ModePos";
DevicePropCodePanasonic[DevicePropCodePanasonic["CameraMode_CreativeMode"] = 33554563] = "CameraMode_CreativeMode";
DevicePropCodePanasonic[DevicePropCodePanasonic["CameraMode_iAMode"] = 33554564] = "CameraMode_iAMode";
// ImageFormat = 0x020000a2, // Duplicated with ImageMode_Quality
DevicePropCodePanasonic[DevicePropCodePanasonic["MeteringInfo"] = 33554608] = "MeteringInfo";
DevicePropCodePanasonic[DevicePropCodePanasonic["IntervalInfo"] = 33554624] = "IntervalInfo";
DevicePropCodePanasonic[DevicePropCodePanasonic["RecDispConfig"] = 33554656] = "RecDispConfig";
DevicePropCodePanasonic[DevicePropCodePanasonic["RecInfoFlash"] = 33554704] = "RecInfoFlash";
DevicePropCodePanasonic[DevicePropCodePanasonic["BurstBracket"] = 33554752] = "BurstBracket";
DevicePropCodePanasonic[DevicePropCodePanasonic["RecPreviewConfig"] = 33554800] = "RecPreviewConfig";
DevicePropCodePanasonic[DevicePropCodePanasonic["RecInfoSelfTimer"] = 33554848] = "RecInfoSelfTimer";
DevicePropCodePanasonic[DevicePropCodePanasonic["RecInfoFlash2"] = 33554864] = "RecInfoFlash2";
DevicePropCodePanasonic[DevicePropCodePanasonic["RecCtrlRelease"] = 50331664] = "RecCtrlRelease";
DevicePropCodePanasonic[DevicePropCodePanasonic["ImageMode"] = 33554592] = "ImageMode";
DevicePropCodePanasonic[DevicePropCodePanasonic["ImageMode_Param"] = 33554593] = "ImageMode_Param";
DevicePropCodePanasonic[DevicePropCodePanasonic["ImageMode_Quality"] = 33554594] = "ImageMode_Quality";
DevicePropCodePanasonic[DevicePropCodePanasonic["ImageMode_ImageAspect"] = 33554595] = "ImageMode_ImageAspect";
DevicePropCodePanasonic[DevicePropCodePanasonic["Liveview_TransImg"] = 226492433] = "Liveview_TransImg";
DevicePropCodePanasonic[DevicePropCodePanasonic["Liveview_RecomImg"] = 226492434] = "Liveview_RecomImg";
})(DevicePropCodePanasonic || (DevicePropCodePanasonic = {}));
var ObjectFormatCodePanasonic;
(function (ObjectFormatCodePanasonic) {
ObjectFormatCodePanasonic[ObjectFormatCodePanasonic["Raw"] = 14336] = "Raw";
})(ObjectFormatCodePanasonic || (ObjectFormatCodePanasonic = {}));
export class TethrPanasonic extends TethrPTPUSB {
constructor(device) {
super(device);
}
async open() {
await super.open();
await this.device.sendCommand({
label: 'Panasonic OpenSession',
opcode: OpCodePanasonic.OpenSession,
parameters: [0x00010001],
});
this.device.onEventCode(EventCodePanasonic.DevicePropChanged, this.onDevicePropChanged);
}
async close() {
await this.device.sendCommand({
label: 'Panasonic CloseSession',
opcode: OpCodePanasonic.CloseSession,
parameters: [0x00010001],
});
await super.open();
}
// Config
setAperture(value) {
return this.setDevicePropValuePanasonic({
devicePropCode: DevicePropCodePanasonic.Aperture_Param,
encode: (value) => {
return value === 'auto' ? 0 : Math.round(value * 10);
},
valueSize: 2,
value,
});
}
getApertureDesc() {
return this.getDevicePropDescPanasonic({
devicePropCode: DevicePropCodePanasonic.Aperture,
decode: (value) => {
return value / 10;
},
valueSize: 2,
});
}
setColorMode(value) {
return this.setDevicePropValuePanasonic({
devicePropCode: DevicePropCodePanasonic.PhotoStyle_Param,
encode: (value) => {
return this.colorModeTable.getKey(value) ?? null;
},
valueSize: 2,
value,
});
}
getColorModeDesc() {
return this.getDevicePropDescPanasonic({
devicePropCode: DevicePropCodePanasonic.PhotoStyle,
decode: (value) => {
return this.colorModeTable.get(value) ?? null;
},
valueSize: 2,
});
}
getExposureModeDesc() {
return this.getDevicePropDescPanasonic({
devicePropCode: DevicePropCodePanasonic.CameraMode_ModePos,
decode: (value) => {
return this.exposureModeTable.get(value) ?? null;
},
valueSize: 2,
});
}
setExposureComp(value) {
return this.setDevicePropValuePanasonic({
devicePropCode: DevicePropCodePanasonic.Exposure_Param,
encode: v => {
if (v === '0')
return 0x0;
let negative = false, digits = 0, thirds = 0;
const match1 = v.match(/^([+-]?)([0-9]+)( 1\/3| 2\/3)?$/);
if (match1) {
negative = match1[1] === '-';
digits = parseInt(match1[2]);
thirds = !match1[3] ? 0 : match1[3] === ' 1/3' ? 1 : 2;
}
const match2 = !match1 && v.match(/^([+-]?)(1\/3|2\/3)$/);
if (match2) {
negative = match2[1] === '-';
thirds = match2[2] === '1/3' ? 1 : 2;
}
if (!match1 && !match2)
return null;
const steps = digits * 3 + thirds;
return (negative ? 0x8000 : 0x0000) | steps;
},
valueSize: 2,
value,
});
}
getExposureCompDesc() {
return this.getDevicePropDescPanasonic({
devicePropCode: DevicePropCodePanasonic.Exposure,
decode: v => {
if (v === 0x0)
return '0';
const steps = v & 0xf;
const digits = Math.floor(steps / 3);
const thirds = steps % 3;
const negative = v & 0x8000;
const sign = negative ? '-' : '+';
const thirdsSymbol = thirds === 1 ? '1/3' : thirds === 2 ? '2/3' : '';
if (digits === 0)
return sign + thirdsSymbol;
if (thirds === 0)
return sign + digits;
return sign + digits + ' ' + thirdsSymbol;
},
valueSize: 2,
});
}
async getManualFocusOptionsDesc() {
return readonlyConfigDesc([
'near:2',
'near:1',
'far:1',
'far:2',
]);
}
async getCanTakePhotoDesc() {
return readonlyConfigDesc(true);
}
async getCanRunAutoFocusDesc() {
return readonlyConfigDesc(true);
}
async getCanRunManualFocusDesc() {
return readonlyConfigDesc(true);
}
async getCanStartLiveviewDesc() {
return readonlyConfigDesc(true);
}
async setColorTemperature(value) {
return this.setDevicePropValuePanasonic({
devicePropCode: DevicePropCodePanasonic.WhiteBalance_KSet,
encode: value => value,
valueSize: 2,
value,
});
}
async getColorTemperatureDesc() {
return this.getDevicePropDescPanasonic({
devicePropCode: DevicePropCodePanasonic.WhiteBalance_KSet,
decode: data => data,
valueSize: 2,
});
}
setImageAspect(value) {
return this.setDevicePropValuePanasonic({
devicePropCode: DevicePropCodePanasonic.ImageMode_ImageAspect,
encode: (value) => {
return this.imageAspectTable.getKey(value) ?? null;
},
valueSize: 2,
value,
});
}
getImageAspectDesc() {
return this.getDevicePropDescPanasonic({
devicePropCode: DevicePropCodePanasonic.ImageMode_ImageAspect,
decode: (value) => {
return this.imageAspectTable.get(value) ?? null;
},
valueSize: 2,
});
}
setImageQuality(value) {
return this.setDevicePropValuePanasonic({
devicePropCode: DevicePropCodePanasonic.ImageMode_Quality,
encode: (value) => {
return this.imageQualityTable.getKey(value) ?? null;
},
valueSize: 2,
value,
});
}
getImageQualityDesc() {
return this.getDevicePropDescPanasonic({
devicePropCode: DevicePropCodePanasonic.ImageMode_Quality,
decode: (value) => {
return this.imageQualityTable.get(value) ?? null;
},
valueSize: 2,
});
}
setIso(value) {
return this.setDevicePropValuePanasonic({
devicePropCode: DevicePropCodePanasonic.ISO_Param,
encode: value => {
return value === 'auto' ? 0xffffffff : value;
},
valueSize: 4,
value,
});
}
getIsoDesc() {
return this.getDevicePropDescPanasonic({
devicePropCode: DevicePropCodePanasonic.ISO,
decode: (value) => {
if (value === 0xffffffff)
return 'auto';
if (value === 0xfffffffe)
return 'auto'; // i-ISO
return value;
},
valueSize: 4,
});
}
setWhiteBalance(value) {
return this.setDevicePropValuePanasonic({
devicePropCode: DevicePropCodePanasonic.WhiteBalance_Param,
encode: (value) => {
return this.whiteBalanceTable.getKey(value) ?? null;
},
valueSize: 2,
value,
});
}
getWhiteBalanceDesc() {
return this.getDevicePropDescPanasonic({
devicePropCode: DevicePropCodePanasonic.WhiteBalance,
decode: (value) => {
return this.whiteBalanceTable.get(value) ?? null;
},
valueSize: 2,
});
}
async setDevicePropValuePanasonic({ value, valueSize, encode, devicePropCode, }) {
const dataView = new PTPDataView();
const encodedValue = encode(value);
if (encodedValue === null) {
return {
status: 'invalid parameter',
};
}
dataView.writeUint32(devicePropCode);
dataView.writeUint32(valueSize);
if (valueSize === 1)
dataView.writeUint8(encodedValue);
if (valueSize === 2)
dataView.writeUint16(encodedValue);
if (valueSize === 4)
dataView.writeUint32(encodedValue);
const succeed = await this.device.sendData({
label: 'Panasonic SetDevicePropValue',
opcode: OpCodePanasonic.SetDevicePropValue,
parameters: [devicePropCode],
data: dataView.toBuffer(),
});
return {
status: succeed ? 'ok' : 'invalid parameter',
};
}
async getDevicePropDescPanasonic({ devicePropCode, decode, valueSize, }) {
const { data } = await this.device.receiveData({
label: 'Panasonic GetDevicePropDesc',
opcode: OpCodePanasonic.GetDevicePropDesc,
parameters: [devicePropCode],
});
const dataView = new PTPDataView(data);
let getValue;
let getArray;
switch (valueSize) {
case 1:
getValue = dataView.readUint8;
getArray = dataView.readUint8Array;
break;
case 2:
getValue = dataView.readUint16;
getArray = dataView.readUint16Array;
break;
case 4:
getValue = dataView.readUint32;
getArray = dataView.readUint32Array;
break;
}
dataView.skip(4); // devicePropCode
const headerLength = dataView.readUint32();
dataView.goto(headerLength * 4 + 2 * 4);
const value = decode(getValue());
const values = [...getArray()].map(decode).filter(isntNil);
return {
writable: values.length > 0,
value,
option: {
type: 'enum',
values,
},
};
}
setShutterSpeed(value) {
return this.setDevicePropValuePanasonic({
devicePropCode: DevicePropCodePanasonic.ShutterSpeed_Param,
encode: (value) => {
if (value === 'bulb')
return 0xffffffff;
if (value === 'auto')
return 0x0ffffffe;
if (value.startsWith('1/')) {
const denominator = parseInt(value.replace(/^1\//, ''));
return denominator * 1000;
}
// Seconds
const seconds = parseFloat(value);
if (!isNaN(seconds)) {
return Math.round(seconds * 1000) | 0x80000000;
}
return null;
},
valueSize: 4,
value,
});
}
getShutterSpeedDesc() {
return this.getDevicePropDescPanasonic({
devicePropCode: DevicePropCodePanasonic.ShutterSpeed,
decode: (value) => {
switch (value) {
case 0xffffffff:
return 'bulb';
case 0x0fffffff:
return 'auto';
case 0x0ffffffe:
return null;
}
if ((value & 0x80000000) === 0x00000000) {
return `1/${value / 1000}`;
}
else {
return `${(value & 0x7fffffff) / 1000}`;
}
},
valueSize: 4,
});
}
// Actions
async takePhoto({ doDownload = true } = {}) {
const quality = await this.get('imageQuality');
let restNumPhotos = quality?.includes('+') ? 2 : 1;
await this.device.sendCommand({
label: 'Panasonic InitiateCapture',
opcode: OpCodePanasonic.InitiateCapture,
parameters: [0x3000011],
});
const infos = await new Promise(resolve => {
const infos = [];
const onObjectAdded = async (ev) => {
const objectID = ev.parameters[0];
const info = await this.getObjectInfo(objectID);
switch (info.format) {
case 'jpeg':
case 'raw':
infos.push(info);
break;
case 'association':
// Ignore folder
return;
default:
throw new Error('Received unexpected objectFormat' + info.format);
}
if (--restNumPhotos === 0) {
this.device.offEventCode(EventCodePanasonic.ObjectAdded, onObjectAdded);
resolve(infos);
}
};
this.device.onEventCode(EventCodePanasonic.ObjectAdded, onObjectAdded);
});
if (!doDownload) {
return { status: 'ok', value: [] };
}
const objects = [];
for (const info of infos) {
const data = await this.getObject(info.id);
const isRaw = info.format === 'raw';
const type = isRaw ? 'image/x-panasonic-rw2' : 'image/jpeg';
const blob = new Blob([data], { type });
objects.push({ ...info, blob });
}
return { status: 'ok', value: objects };
}
#canvasMediaStream = new CanvasMediaStream();
async startLiveview() {
await this.device.sendCommand({
label: 'Panasonic Liveview',
opcode: OpCodePanasonic.Liveview,
parameters: [0x0d000010],
});
const stream = await this.#canvasMediaStream.begin(this.#updateLiveviewFrame);
this.emit('liveviewChange', readonlyConfigDesc(stream));
this.device.on('idle', this.#updateLiveviewFrame);
return { status: 'ok', value: stream };
}
#updateLiveviewFrame = async () => {
const image = await this.#getLiveviewImage();
if (!image)
return;
const imageBitmap = await createImageBitmap(image);
this.#canvasMediaStream.updateWithImage(imageBitmap);
};
async stopLiveview() {
await this.device.sendCommand({
label: 'Panasonic Liveview',
opcode: OpCodePanasonic.Liveview,
parameters: [0x0d000011],
});
this.device.off('idle', this.#updateLiveviewFrame);
this.emit('liveviewChange', readonlyConfigDesc(null));
return { status: 'ok' };
}
async getLiveviewSizeDesc() {
const setting = await this.getLiveviewSetting();
const settingOptions = await this.getLiveviewRecommendedSettings();
const value = getSizeStringFromSetting(setting);
const values = settingOptions.map(getSizeStringFromSetting);
return {
writable: values.length > 0,
value,
option: {
type: 'enum',
values,
},
};
function getSizeStringFromSetting(setting) {
return `${setting.width}x${setting.height}`;
}
}
async setLiveviewSize(value) {
const [width, height] = value.split('x').map(parseInt);
const settings = await this.getLiveviewRecommendedSettings();
const setting = settings.find(s => s.width === width && s.height === height);
if (!setting) {
return { status: 'invalid parameter' };
}
await this.setLiveviewSetting(setting);
return { status: 'ok' };
}
async getLiveviewRecommendedSettings() {
const { data } = await this.device.receiveData({
opcode: OpCodePanasonic.GetLiveviewSettings,
parameters: [DevicePropCodePanasonic.Liveview_RecomImg],
});
const dataView = new PTPDataView(data);
/*const receivedPropCode =*/ dataView.readUint32();
/*const dataSize =*/ dataView.readUint32();
const settingsNum = dataView.readUint16();
/*const structSize =*/ dataView.readUint16();
const settings = times(settingsNum, () => {
return {
height: dataView.readUint16(),
width: dataView.readUint16(),
frameSize: dataView.readUint16(),
fps: dataView.readUint16(),
};
});
return settings;
}
async getLiveviewSetting() {
const { data } = await this.device.receiveData({
opcode: OpCodePanasonic.GetLiveviewSettings,
parameters: [DevicePropCodePanasonic.Liveview_TransImg],
});
const dataView = new PTPDataView(data);
/*const receivedPropCode =*/ dataView.readUint32();
/*const dataSize =*/ dataView.readUint32();
return {
height: dataView.readUint16(),
width: dataView.readUint16(),
frameSize: dataView.readUint16(),
fps: dataView.readUint16(),
};
}
async setLiveviewSetting(setting) {
const dataView = new PTPDataView();
dataView.writeUint32(DevicePropCodePanasonic.Liveview_TransImg);
dataView.writeUint32(8);
dataView.writeUint16(setting.height);
dataView.writeUint16(setting.width);
dataView.writeUint16(setting.frameSize);
dataView.writeUint16(setting.fps);
await this.device.sendData({
opcode: OpCodePanasonic.SetLiveviewSettings,
parameters: [DevicePropCodePanasonic.Liveview_TransImg],
data: dataView.toBuffer(),
});
}
async #getLiveviewImage() {
const { resCode, data } = await this.device.receiveData({
label: 'Panasonic LiveviewImage',
opcode: OpCodePanasonic.LiveviewImage,
expectedResCodes: [ResCode.OK, ResCode.DeviceBusy],
maxByteLength: 1_000_000, // = 1MB
});
if (resCode !== ResCode.OK)
return null;
// let histogram!: Uint8Array | undefined
const dataView = new DataView(data);
let jpegOffset = 180;
for (let offset = 0; offset < 180;) {
const id = dataView.getUint32(offset, true);
offset += 4;
const dataSize = dataView.getUint32(offset, true);
offset += 4;
// const sessionID = dataView.getUint32(offset, true)
switch (id) {
case 0x17000001: {
// Jpeg Offset
jpegOffset = dataView.getUint32(offset + 4, true);
break;
}
/*
case 0x17000002: {
// Jpeg Length?
jpegLength = dataView.getUint32(offset + 4, true)
break
}*/
case 0x17000003: {
// Histogram
// const valid = dataView.getUint32(offset + 4, true)
// const samples = dataView.getUint32(offset + 8, true)
// const elems = dataView.getUint32(offset + 12, true)
// histogram = new Uint8Array(
// data.slice(offset + 16, offset + 16 + samples)
// )
break;
}
case 0x17000004: {
// Posture?
// const posture = dataView.getUint16(offset + 4, true)
break;
}
case 0x17000005: {
// Level gauge
// const roll = dataView.getInt16(offset + 4, true) / 10
// const pitch = dataView.getInt16(offset + 6, true) / 10
break;
}
}
offset += dataSize;
}
if (!jpegOffset)
return null;
const jpegData = data.slice(jpegOffset);
const image = new Blob([jpegData], { type: 'image/jpg' });
return image;
}
async runManualFocus(option) {
const [direction, speed] = option.split(':');
let mode = 0;
if (direction === 'far') {
if (speed === '1')
mode = 2;
else if (speed === '2')
mode = 1;
}
else if (direction === 'near') {
if (speed === '1')
mode = 3;
else if (speed === '2')
mode = 4;
}
if (!mode) {
return { status: 'invalid parameter' };
}
const devicePropCode = 0x03010011;
const dataView = new PTPDataView();
dataView.writeUint32(devicePropCode);
dataView.writeUint32(2);
dataView.writeUint16(mode);
await this.device.sendData({
label: 'Panasonic ManualFocusDrive',
opcode: OpCodePanasonic.ManualFocusDrive,
parameters: [devicePropCode],
data: dataView.toBuffer(),
});
return { status: 'ok' };
}
async runAutoFocus() {
await this.device.sendCommand({
label: 'Panasonic Ctrl Liveview',
opcode: OpCodePanasonic.CtrlLiveview,
parameters: [0x03000024],
});
return { status: 'ok' };
}
onDevicePropChanged = async (ev) => {
const devicdPropCode = ev.parameters[0];
let configs;
switch (devicdPropCode) {
case DevicePropCodePanasonic.CameraMode:
configs = ['exposureMode', 'aperture', 'shutterSpeed', 'exposureComp'];
break;
case DevicePropCodePanasonic.Aperture:
configs = ['aperture'];
break;
case DevicePropCodePanasonic.ShutterSpeed:
configs = ['shutterSpeed'];
break;
case DevicePropCodePanasonic.ISO:
configs = ['iso'];
break;
case DevicePropCodePanasonic.Exposure:
configs = ['exposureComp'];
break;
case DevicePropCodePanasonic.WhiteBalance:
configs = ['whiteBalance', 'colorTemperature'];
break;
case DevicePropCodePanasonic.PhotoStyle:
configs = ['colorMode'];
break;
case DevicePropCodePanasonic.ImageMode:
configs = ['imageSize', 'imageAspect', 'imageQuality'];
break;
default:
return;
}
for (const config of configs) {
const desc = await this.getDesc(config);
this.emit(`${config}Change`, desc);
}
};
getObjectFormat(code) {
return (ObjectFormatCode[code] ?? ObjectFormatCodePanasonic[code]).toLowerCase();
}
exposureModeTable = new BiMap([
[0, 'P'],
[1, 'A'],
[2, 'S'],
[3, 'M'],
[5, 'video'],
[7, 'vendor:iA'],
[8, 'C1'],
[9, 'C2'],
[10, 'C3'],
[12, 'vendor:S&Q'],
]);
whiteBalanceTable = new BiMap([
[0x0002, 'auto'],
[0x0004, 'daylight'],
[0x8008, 'cloud'],
[0x0006, 'incandescent'],
// [0x8009, 'White Set'],
[0x0007, 'flash'],
[0x0005, 'fluorescent'],
// [0x800a, 'Black and White'],
// [0x800b, 'WB Setting 1'],
// [0x800c, 'WB Setting 2'],
// [0x800d, 'WB Setting 3'],
// [0x800e, 'WB Setting 4'],
[0x800f, 'shade'],
[0x8010, 'vendor:manual'],
[0x8011, 'vendor:manual2'],
[0x8012, 'vendor:manual3'],
[0x8013, 'vendor:manual4'],
[0x8014, 'auto cool'],
[0x8015, 'auto warm'],
]);
colorModeTable = new BiMap([
[0, 'Standard'],
[1, 'Vivid'],
[2, 'Natural'],
[44, 'L.Classic Neo'],
[18, 'Flat'],
[4, 'Landscape'],
[5, 'Portrait'],
[3, 'Monochorme'],
[15, 'L.Monochrome'],
[17, 'L.Monochrome D'],
[45, 'L.Monochrome S'],
[50, 'LEICA Monochrome'],
[41, 'Cinelike D2'],
[42, 'Cinelike V2'],
[14, 'Like709'],
[40, 'V-Log'],
[49, 'Realtime LUT'],
[19, 'MY PHOTOSTYLE 1'],
[20, 'MY PHOTOSTYLE 2'],
[21, 'MY PHOTOSTYLE 3'],
[22, 'MY PHOTOSTYLE 4'],
]);
imageAspectTable = new BiMap([
[1, '4:3'],
[2, '3:2'],
[3, '16:9'],
[4, '1:1'],
[10, '65:24'],
[11, '2:1'],
]);
imageQualityTable = new BiMap([
[0, 'fine'],
[1, 'standard'],
[2, 'raw'],
[3, 'raw,fine'],
[4, 'raw,standard'],
]);
}
//# sourceMappingURL=TethrPanasonic.js.map