Skip to content

Commit

Permalink
- New output that emits both the base64 and file as well as the cropp…
Browse files Browse the repository at this point in the history
…ed image height & width and the cropper's position

- Deprecated `imageCroppedBase64` and `imageCroppedFile`
- Reset the cropper when changing the `aspectRatio` dynamically
  • Loading branch information
Mawi137 committed Oct 7, 2018
1 parent 5fe2c12 commit 04b7b09
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 30 deletions.
39 changes: 29 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Add the element to your HTML:
[aspectRatio]="4 / 3"
[resizeToWidth]="128"
format="png"
(imageCroppedBase64)="imageCropped($event)"
(imageCropped)="imageCropped($event)"
(imageLoaded)="imageLoaded()"
(loadImageFailed)="loadImageFailed()"
></image-cropper>
Expand All @@ -57,8 +57,8 @@ croppedImage: any = '';
fileChangeEvent(event: any): void {
this.imageChangedEvent = event;
}
imageCropped(image: string) {
this.croppedImage = image;
imageCropped(event: ImageCroppedEvent) {
this.croppedImage = event.base64;
}
imageLoaded() {
// show cropper
Expand All @@ -77,7 +77,7 @@ All inputs are optional. Either the `imageChangedEvent` or `imageBase64` should
| Name | Type | Default | Description |
| ---------------------- |---------- | ------------ | --------------- |
| `imageChangedEvent` | FileEvent | | The change event from your file input (set to `null` to reset the cropper) |
| `imageFileChanged` | File | | The file you want to change (set to `null` to reset the cropper) |
| `imageFileChanged` | Blob(File)| | The file you want to change (set to `null` to reset the cropper) |
| `imageBase64` | string | | If you don't want to use a file input, you can set a base64 image directly and it will be loaded into the cropper |
| `format` | string | png | Output format (png, jpeg, webp, bmp, ico) (not all browsers support all types, png is always supported, others are optional) |
| `maintainAspectRatio` | boolean | true | Keep width and height of cropped image equal according to the aspectRatio |
Expand All @@ -88,9 +88,28 @@ All inputs are optional. Either the `imageChangedEvent` or `imageBase64` should
| `imageQuality` | number | 92 | This only applies when using jpeg or webp as output format. Entering a number between 0 and 100 will determine the quality of the output image. |

### Outputs
| Name | Type | Description |
| ----------------------- | ------ | ----------- |
| `imageCroppedBase64` | string | Emits a Base64 string of the cropped image each time it is cropped |
| `imageCroppedFile` | File | Emits the cropped image as a file each time it is cropped |
| `imageLoaded` | void | Emits when the image was loaded into the cropper |
| `loadImageFailed` | void | Emits when a wrong file type was selected (only png, gif and jpg are allowed) |
| Name | Type | Description |
| ----------------------- | ----------------- | ----------- |
| `imageCropped` | ImageCroppedEvent | Emits a ImageCroppedEvent image each time it is cropped |
| **(DEPRECATED)** `imageCroppedBase64` | string | Emits a Base64 string of the cropped image each time it is cropped |
| **(DEPRECATED)** `imageCroppedFile` | File | Emits the cropped image as a file each time it is cropped |
| `imageLoaded` | void | Emits when the image was loaded into the cropper |
| `loadImageFailed` | void | Emits when a wrong file type was selected (only png, gif and jpg are allowed) |

### Interfaces
#### CropperPosition
| Property | Type | Description |
| -------- | ------ | ----------- |
| x1 | number | X position of first coordinate (in px) |
| y1 | number | Y position of first coordinate (in px) |
| x2 | number | X position of second coordinate (in px) |
| y2 | number | Y position of second coordinate (in px) |

#### ImageCroppedEvent
| Property | Type | Description |
| --------------- | ------ | ----------- |
| base64 | string | Base64 string of the cropped image |
| file | Blob(File) | Blob of the cropped image |
| width | number | Width of the cropped image |
| height | number | Height of the cropped image |
| croppedPosition | CropperPosition | Position of the cropper when it was cropped |
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ngx-image-cropper",
"version": "1.0.2",
"version": "1.1.0",
"description": "An image cropper for Angular",
"main": "./bundles/ngx-image-cropper.umd.js",
"module": "./ngx-image-cropper/ngx-image-cropper.es5.js",
Expand Down
53 changes: 34 additions & 19 deletions src/image-cropper.component.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
import {
Component,
ElementRef,
EventEmitter,
HostListener,
Input,
OnChanges,
Output,
SimpleChanges,
ChangeDetectorRef,
ChangeDetectionStrategy
Component, ElementRef, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges,
ChangeDetectorRef, ChangeDetectionStrategy
} from '@angular/core';
import { DomSanitizer, SafeUrl, SafeStyle } from '@angular/platform-browser';
import { ImageUtils } from './image.utils';
Expand Down Expand Up @@ -37,6 +29,14 @@ export interface CropperPosition {
y2: number;
}

export interface ImageCroppedEvent {
base64: string;
file: Blob;
width: number;
height: number;
cropperPosition: CropperPosition;
}

@Component({
selector: 'image-cropper',
templateUrl: './image-cropper.component.html',
Expand Down Expand Up @@ -89,8 +89,10 @@ export class ImageCropperComponent implements OnChanges {
y2: 10000
};


@Output() imageCropped = new EventEmitter<ImageCroppedEvent>();
@Output() imageCroppedBase64 = new EventEmitter<string>();
@Output() imageCroppedFile = new EventEmitter<File>();
@Output() imageCroppedFile = new EventEmitter<Blob>();
@Output() imageLoaded = new EventEmitter<void>();
@Output() loadImageFailed = new EventEmitter<void>();

Expand All @@ -107,6 +109,9 @@ export class ImageCropperComponent implements OnChanges {
this.cd.markForCheck();
});
}
if (changes['aspectRatio']) {
this.resetCropperPosition();
}
}

private initCropper() {
Expand Down Expand Up @@ -416,24 +421,34 @@ export class ImageCropperComponent implements OnChanges {
const width = Math.round((this.cropper.x2 - this.cropper.x1) * ratio);
const height = Math.round((this.cropper.y2 - this.cropper.y1) * ratio);
const resizeRatio = this.getResizeRatio(width);
const resizedWidth = Math.floor(width * resizeRatio);
const resizedHeight = Math.floor(height * resizeRatio);

const cropCanvas = document.createElement('canvas') as HTMLCanvasElement;
cropCanvas.width = width * resizeRatio;
cropCanvas.height = height * resizeRatio;
cropCanvas.width = resizedWidth;
cropCanvas.height = resizedHeight;

const ctx = cropCanvas.getContext('2d');
if (ctx) {
ctx.drawImage(this.originalImage, left, top, width, height, 0, 0, width * resizeRatio, height * resizeRatio);
const quality = Math.min(1, Math.max(0, this.imageQuality / 100));
const croppedImage = cropCanvas.toDataURL(`image/${this.format}`, quality);
const croppedImage = cropCanvas.toDataURL('image/' + this.format, quality);
if (croppedImage.length > 10) {
this.imageCroppedBase64.emit(croppedImage);
}
cropCanvas.toBlob(
(fileImage: File) => this.imageCroppedFile.emit(fileImage),
`image/${this.format}`,
quality,
);
const toBlobCallback = (imageFile: Blob | null) => {
if (imageFile != null) {
this.imageCroppedFile.emit(imageFile);
this.imageCropped.emit({
base64: croppedImage,
file: imageFile,
width: resizedWidth,
height: resizedHeight,
cropperPosition: Object.assign({}, this.cropper)
});
}
};
cropCanvas.toBlob(toBlobCallback, 'image/' + this.format, quality);
}
}
}
Expand Down

0 comments on commit 04b7b09

Please sign in to comment.