Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/sabine/svelte-crop-window
Image and video cropper Svelte component with gesture and mouse support
https://github.com/sabine/svelte-crop-window
crop gestures image-cropper rotate svelte svelte-component video-cropper zoom
Last synced: about 1 month ago
JSON representation
Image and video cropper Svelte component with gesture and mouse support
- Host: GitHub
- URL: https://github.com/sabine/svelte-crop-window
- Owner: sabine
- License: mit
- Created: 2022-10-06T19:41:18.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2024-01-11T02:29:43.000Z (12 months ago)
- Last Synced: 2024-11-30T06:49:04.885Z (about 1 month ago)
- Topics: crop, gestures, image-cropper, rotate, svelte, svelte-component, video-cropper, zoom
- Language: Svelte
- Homepage: https://sabine.github.io/svelte-crop-window/
- Size: 36.2 MB
- Stars: 33
- Watchers: 1
- Forks: 1
- Open Issues: 9
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# svelte-crop-window
A crop window component for images and videos that supports touch gestures (pinch zoom, rotate, pan), as well as mousewheel zoom, mouse-dragging the image, and rotating on right mouse button.
Currently looking for contributors / feature requests / feedback to help improve this component.
![video cropper](/static/videocrop.gif)
If you can do code-review, that's very welcome.
Here's a [demo page](https://sabine.github.io/svelte-crop-window/).
And here's a [minimal REPL where you can play with the code](https://svelte.dev/repl/2db644efd08841958f2dd3209f00bf51?version=3.52.0) and a [fancier REPL](https://svelte.dev/repl/c246300e4ffd42a0b01ff318f7abd91d?version=3.52.0).
## Installation
```bash
npm install svelte-crop-window
```## Basic use
You must wrap the `CropWindow` component with an Element that determines the height.
```htmlimport { CropWindow, defaultValue } from 'svelte-crop-window';
let media = {
content_type: 'image',
url: '/svelte-crop-window/hintersee-3601004.jpg'
};let value = { ...defaultValue };
```## `CropWindow.svelte` Component
### Props
| name | type | required | purpose |
| --------- | ----------------------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------- |
| `media` | `Media` | ✓ | image or video to be cropped |
| `value` | `CropValue` | | value that describes [how to crop](#how-to-crop) - will be initialized if undefined |
| `options` | [`Options`](#options) | | options for the crop window and overlay, see below |```typescript
type Media = {
content_type: 'image' | 'video';
url: string;
}type CropValue = {
position: { x: number; y: number };
aspect: number;
rotation: number;
scale: number; }
}const defaultValue: CropValue = {
position: { x: 0, y: 0 },
aspect: 1.0,
rotation: 0,
scale: 0
};
```### Options
| name | type | purpose |
| -------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `shape` | `'rect' \| 'round'` | shape of the crop area (yes, an ellipse will work) |
| `crop_window_margin` | `number` | Margin of the crop window, in pixels. The crop window will always scale to the maximum possible size in its containing element. |
| `overlay` | a Svelte component | The overlay component which visually highlights the crop area. You can pass your own Svelte component with props `options: T, gesture_in_progress: boolean, shape: 'rect' \| 'round'` here, or use the included [Overlay.svelte](/src/lib/overlay/Overlay.svelte). |
| `overlay_options` | `T` | Options for your overlay component. See below for the options of the included overlay component. |```typescript
const defaultOptions: Options = {
shape: 'rect',
crop_window_margin: 10,
overlay: Overlay,
overlay_options: defaultOverlayOptions
};
```## `Overlay.svelte` Component
### Options
| name | type | purpose |
| ------------------ | --------- | -------------------------------------------------------------------- |
| `overlay_color` | `string` | the color of the overlay that covers everything except the crop area |
| `line_color` | `string` | the color of the lines |
| `show_third_lines` | `boolean` | whether to show third lines or not when a gesture is in progress |```typescript
const defaultOverlayOptions: OverlayOptions = {
overlay_color: 'rgb(11, 11, 11, 0.7)',
line_color: 'rgba(167, 167, 167, 0.5)',
show_third_lines: true
};
```## How to Crop
### Display in HTML Without Actually Cropping:
```html
```Note: You must choose a `HEIGHT`, because the crop value is normalized against the target height.
### Pseudo Code to Crop
1. Choose a `target_height` and calculate the `target_width` for the cropped image:
```javascript
let target_width = value.aspect * target_height;
```2. Calculate factor `s` by which to scale:
```javascript
let s = (value.scale * target_height) / media.height;
```3. Scale media by `s`:
```javascript
let resized_media = scale(media, s);
```4. Rotate media by `value.rotation`:
```javascript
let resized_and_rotated_media = rotate(resized_media, value.rotation);
```5. Calculate top left position of the area to extract:
```javascript
let left = (resized_and_rotated_media.width - target_width) / 2.0
- value.x * target_height;
let top = (resized_and_rotated_media.height - target_height) / 2.0
- value.y * target_height;
```6. Extract area:
```javascript
let cropped_media =
extract_area(resized_and_rotated_media,
left, top, target_width, target_height);
```## What this component doesn't do
1. Does not modify/crop the image, you have to do that by whatever means make sense for your application. Doesn't (yet) provide usable controls. Currently, you need to implement your own.
2. Similar to the overlay, it would be nice to include some controls to make this more usable out of the box. Contributions are very welcome.## Developing
Once you've cloned the project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev# or start the server and open the app in a new browser tab
npm run dev -- --open
```## Acknowledgements
One big inspiration for this component was the Android library
[uCrop by Yalantis](https://github.com/Yalantis/uCrop). What is particularly
valuable is that the developers shared their thought process in
[this blog post](https://yalantis.com/blog/how-we-created-ucrop-our-own-image-cropping-library-for-android/).Another very helpful resource was [svelte-easy-crop](https://www.npmjs.com/package/svelte-easy-crop)
which gave me a basic understanding of how to implement a crop window component in Svelte
(and HTML/JS in general).There's no code reuse between either of these components and this one. All
calculations had to be recreated from textbook math.