Skip to content

Commit 56dd3fd

Browse files
committed
add support for high resolution images in fileComp
1 parent a2b4c12 commit 56dd3fd

File tree

4 files changed

+49
-7
lines changed

4 files changed

+49
-7
lines changed

client/packages/lowcoder/src/comps/comps/fileComp/ImageCaptureModal.tsx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { Suspense, useCallback, useEffect, useRef, useState } from "react";
1+
import React, { Suspense, useCallback, useEffect, useMemo, useRef, useState } from "react";
22
import { default as Button } from "antd/es/button";
33
import Dropdown from "antd/es/dropdown";
44
import type { ItemType } from "antd/es/menu/interface";
@@ -8,6 +8,7 @@ import Flex from "antd/es/flex";
88
import styled from "styled-components";
99
import { trans } from "i18n";
1010
import { CustomModal } from "lowcoder-design";
11+
import { CaptureResolution, RESOLUTION_CONSTRAINTS } from "./fileComp";
1112

1213
const CustomModalStyled = styled(CustomModal)`
1314
top: 10vh;
@@ -53,23 +54,32 @@ const ReactWebcam = React.lazy(() => import("react-webcam"));
5354

5455
export const ImageCaptureModal = (props: {
5556
showModal: boolean;
57+
captureResolution?: CaptureResolution;
5658
onModalClose: () => void;
5759
onImageCapture: (image: string) => void;
5860
}) => {
5961
const [errMessage, setErrMessage] = useState("");
60-
const [videoConstraints, setVideoConstraints] = useState<MediaTrackConstraints>({
61-
facingMode: "environment",
62-
});
62+
const [selectedDeviceId, setSelectedDeviceId] = useState<string | null>(null);
6363
const [modeList, setModeList] = useState<ItemType[]>([]);
6464
const [dropdownShow, setDropdownShow] = useState(false);
6565
const [imgSrc, setImgSrc] = useState<string>();
6666
const webcamRef = useRef<any>(null);
6767

68+
const resolution = props.captureResolution ?? "auto";
69+
const resolutionSize = RESOLUTION_CONSTRAINTS[resolution] ?? {};
70+
71+
const videoConstraints = useMemo<MediaTrackConstraints>(() => {
72+
const base: MediaTrackConstraints = selectedDeviceId
73+
? { deviceId: { exact: selectedDeviceId } }
74+
: { facingMode: "environment" };
75+
return { ...base, ...resolutionSize };
76+
}, [selectedDeviceId, resolutionSize]);
77+
6878
useEffect(() => {
6979
if (props.showModal) {
7080
setImgSrc("");
7181
setErrMessage("");
72-
setVideoConstraints({ facingMode: "environment" });
82+
setSelectedDeviceId(null);
7383
setDropdownShow(false);
7484
}
7585
}, [props.showModal]);
@@ -125,6 +135,8 @@ export const ImageCaptureModal = (props: {
125135
ref={webcamRef}
126136
onUserMediaError={handleMediaErr}
127137
screenshotFormat="image/jpeg"
138+
screenshotQuality={1}
139+
forceScreenshotSourceSize
128140
videoConstraints={videoConstraints}
129141
/>
130142
</Suspense>
@@ -172,7 +184,7 @@ export const ImageCaptureModal = (props: {
172184
<Menu
173185
items={modeList}
174186
onClick={(value) => {
175-
setVideoConstraints({ deviceId: { exact: value.key } });
187+
setSelectedDeviceId(value.key);
176188
setDropdownShow(false);
177189
}}
178190
/>

client/packages/lowcoder/src/comps/comps/fileComp/draggerUpload.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
multiChangeAction,
1212
} from "lowcoder-core";
1313
import { hasIcon } from "comps/utils";
14-
import { resolveValue, resolveParsedValue, commonProps, validateFile } from "./fileComp";
14+
import { resolveValue, resolveParsedValue, commonProps, validateFile, CaptureResolution } from "./fileComp";
1515
import { FileStyleType, AnimationStyleType, heightCalculator, widthCalculator } from "comps/controls/styleControlConstants";
1616
import { ImageCaptureModal } from "./ImageCaptureModal";
1717
import { v4 as uuidv4 } from "uuid";
@@ -148,6 +148,7 @@ interface DraggerUploadProps {
148148
prefixIcon: any;
149149
suffixIcon: any;
150150
forceCapture: boolean;
151+
captureResolution: CaptureResolution;
151152
minSize: number;
152153
maxSize: number;
153154
maxFiles: number;
@@ -291,6 +292,7 @@ export const DraggerUpload = (props: DraggerUploadProps) => {
291292

292293
<ImageCaptureModal
293294
showModal={showModal}
295+
captureResolution={props.captureResolution as CaptureResolution}
294296
onModalClose={() => setShowModal(false)}
295297
onImageCapture={async (image) => {
296298
setShowModal(false);

client/packages/lowcoder/src/comps/comps/fileComp/fileComp.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,22 @@ const validationChildren = {
100100
fileNamePattern: StringControl,
101101
};
102102

103+
export type CaptureResolution = "auto" | "1080p" | "720p" | "480p";
104+
105+
export const CaptureResolutionOptions = [
106+
{ label: trans("file.captureResolutionAuto"), value: "auto" },
107+
{ label: trans("file.captureResolution1080p"), value: "1080p" },
108+
{ label: trans("file.captureResolution720p"), value: "720p" },
109+
{ label: trans("file.captureResolution480p"), value: "480p" },
110+
] as const;
111+
112+
export const RESOLUTION_CONSTRAINTS: Record<CaptureResolution, { width?: number; height?: number }> = {
113+
auto: {},
114+
"1080p": { width: 1920, height: 1080 },
115+
"720p": { width: 1280, height: 720 },
116+
"480p": { width: 640, height: 480 },
117+
};
118+
103119
const commonChildren = {
104120
value: stateComp<Array<string | null>>([]),
105121
files: stateComp<JSONObject[]>([]),
@@ -114,6 +130,7 @@ const commonChildren = {
114130
prefixIcon: withDefault(IconControl, "/icon:solid/arrow-up-from-bracket"),
115131
suffixIcon: IconControl,
116132
forceCapture: BoolControl,
133+
captureResolution: dropdownControl(CaptureResolutionOptions, "auto"),
117134
...validationChildren,
118135
};
119136

@@ -441,6 +458,7 @@ const Upload = (
441458

442459
<ImageCaptureModal
443460
showModal={showModal}
461+
captureResolution={props.captureResolution as CaptureResolution}
444462
onModalClose={() => setShowModal(false)}
445463
onImageCapture={async (image) => {
446464
setShowModal(false);
@@ -548,6 +566,10 @@ let FileTmpComp = new UICompBuilder(childrenMap, (props, dispatch) => {
548566
label: trans("file.forceCapture"),
549567
tooltip: trans("file.forceCaptureTooltip")
550568
})}
569+
{children.forceCapture.getView() && children.captureResolution.propertyView({
570+
label: trans("file.captureResolution"),
571+
tooltip: trans("file.captureResolutionTooltip"),
572+
})}
551573
{children.showUploadList.propertyView({ label: trans("file.showUploadList") })}
552574
{children.parseFiles.propertyView({
553575
label: trans("file.parseFiles"),

client/packages/lowcoder/src/i18n/locales/en.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1954,6 +1954,12 @@ export const en = {
19541954
"fileNamePatternPlaceholder": "^[a-zA-Z0-9_-]+\\.[a-z]+$",
19551955
"fileNamePatternErrorMsg": "Upload Failed. The File Name Does Not Match the Required Pattern.",
19561956
"invalidFileNamePatternMsg": "Invalid File Name Pattern: {error}",
1957+
"captureResolution": "Capture Resolution",
1958+
"captureResolutionTooltip": "Set the camera resolution for image capture. Higher resolutions produce better quality but may not be supported by all cameras.",
1959+
"captureResolutionAuto": "Auto (Camera Default)",
1960+
"captureResolution1080p": "1080p",
1961+
"captureResolution720p": "720p",
1962+
"captureResolution480p": "480p",
19571963
},
19581964
"date": {
19591965
"format": "Format",

0 commit comments

Comments
 (0)