Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add method to get screenshot as a Blob instead of base64-encoded string #411

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 41 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,29 @@ You may also pass in an optional `dimensions` object:
getScreenshot({width: 1920, height: 1080});
```

`getScreenshotBlob` - Returns a Promise that resolves to a Blob of the current webcam image. This is more efficient than base64 encoding when uploading to a server or processing large images. Example:

```jsx
const capture = async () => {
try {
const blob = await webcamRef.current.getScreenshotBlob({width: 1920, height: 1080});
if (blob) {
// Upload to a server
const formData = new FormData();
formData.append('image', blob);
await fetch('/upload', { method: 'POST', body: formData });

// Or create an object URL for display
const url = URL.createObjectURL(blob);
image.src = url;
URL.revokeObjectURL(url); // Clean up when done
}
} catch (error) {
console.error('Failed to capture screenshot:', error);
}
};
```

### The Constraints

We can build a constraints object by passing it to the videoConstraints prop. This gets passed into getUserMedia method. Please take a look at the MDN docs to get an understanding how this works.
Expand All @@ -95,14 +118,23 @@ const WebcamCapture = () => (
width={1280}
videoConstraints={videoConstraints}
>
{({ getScreenshot }) => (
<button
onClick={() => {
const imageSrc = getScreenshot()
}}
>
Capture photo
</button>
{({ getScreenshot, getScreenshotBlob }) => (
<div>
<button
onClick={() => {
const imageSrc = getScreenshot()
}}
>
Capture photo (base64)
</button>
<button
onClick={async () => {
const blob = await getScreenshotBlob();
}}
>
Capture photo (blob)
</button>
</div>
)}
</Webcam>
);
Expand All @@ -121,7 +153,7 @@ const WebcamCapture = () => {
const webcamRef = React.useRef(null);
const capture = React.useCallback(
() => {
const imageSrc = webcamRef.current.getScreenshot();
const imageSrc = webcamRef.current.getScreenshot(); // or getScreenshotBlob()
},
[webcamRef]
);
Expand Down
33 changes: 33 additions & 0 deletions src/react-webcam.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ interface ScreenshotDimensions {

interface ChildrenProps {
getScreenshot: (screenshotDimensions?: ScreenshotDimensions) => string | null;
getScreenshotBlob: (screenshotDimensions?: ScreenshotDimensions) => Promise<Blob | null>;
}

export type WebcamProps = Omit<React.HTMLProps<HTMLVideoElement>, "ref"> & {
Expand Down Expand Up @@ -204,6 +205,37 @@ export default class Webcam extends React.Component<WebcamProps, WebcamState> {
);
}

async getScreenshotBlob(screenshotDimensions?: ScreenshotDimensions): Promise<Blob | null> {
const { state, props } = this;

if (!state.hasUserMedia) return null;

const canvas = this.getCanvas(screenshotDimensions);
if (!canvas) return null;

if (typeof canvas.toBlob !== 'function') {
throw new Error('Canvas toBlob is not supported');
}

try {
const blob = await new Promise<Blob | null>((resolve) => {
canvas.toBlob(
(blob) => resolve(blob),
props.screenshotFormat,
props.screenshotQuality
);
});

if (!blob) {
throw new Error('Failed to convert canvas to blob');
}

return blob;
} catch (error) {
throw error instanceof Error ? error : new Error('Failed to capture screenshot');
}
}

getCanvas(screenshotDimensions?: ScreenshotDimensions) {
const { state, props } = this;

Expand Down Expand Up @@ -404,6 +436,7 @@ export default class Webcam extends React.Component<WebcamProps, WebcamState> {

const childrenProps: ChildrenProps = {
getScreenshot: this.getScreenshot.bind(this),
getScreenshotBlob: this.getScreenshotBlob.bind(this),
};

return (
Expand Down