
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
crop-image-pro
Advanced tools
Professional image cropping library with HEIC support, compression, and easy integration. Framework-agnostic vanilla JavaScript/TypeScript solution.
Professional image cropping library with HEIC support, compression, and easy integration. Framework-agnostic vanilla JavaScript/TypeScript solution that works seamlessly with any web application.
✅ Framework Agnostic - Works with vanilla JS, React, Vue, Angular, Svelte, or any other framework
✅ HEIC Support - Automatically converts HEIC/HEIF images to JPEG
✅ Image Compression - Built-in compression to reduce file sizes
✅ Aspect Ratio Control - Lock or unlock aspect ratios
✅ Zoom & Rotate - Full image transformation controls
✅ TypeScript Support - Full type definitions included
✅ Responsive Design - Mobile-friendly with touch support
✅ Accessible - ARIA labels and keyboard navigation
✅ Dark Mode Ready - Automatic dark mode support
✅ Zero Dependencies (except heic2any for HEIC conversion)
npm install crop-image-pro
or
yarn add crop-image-pro
import CropImagePro from "crop-image-pro";
// CSS is automatically embedded - no need to import separately!
// Optional: import "crop-image-pro/css" if you prefer external CSS
// Get file from input
const fileInput = document.getElementById("file-input");
fileInput.addEventListener("change", async (e) => {
const file = e.target.files[0];
if (file) {
const cropper = new CropImagePro(file, "my-image", {
aspectRatio: 1, // Square crop
maxOutputSize: 1200,
compressionQuality: 0.7,
});
try {
const result = await cropper.open();
// Use the cropped image
console.log("Cropped file:", result.file);
console.log("Preview URL:", result.previewUrl);
// Display preview
const img = document.createElement("img");
img.src = result.previewUrl;
document.body.appendChild(img);
// Upload to server
const formData = new FormData();
formData.append("image", result.file);
await fetch("/api/upload", {
method: "POST",
body: formData,
});
} catch (error) {
console.log("User cancelled or error occurred:", error);
}
}
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Crop Image Pro Demo</title>
<!-- CSS is embedded automatically, but you can also use standalone: -->
<!-- <link rel="stylesheet" href="node_modules/crop-image-pro/dist/cropImagePro.css" /> -->
</head>
<body>
<input type="file" id="file-input" accept="image/*,.heic" />
<script type="module">
import CropImagePro from "./node_modules/crop-image-pro/dist/cropImagePro.js";
// Your code here
</script>
</body>
</html>
import React, { useState } from "react";
import CropImagePro from "crop-image-pro";
// CSS is embedded - no import needed!
function ImageUploader() {
const [preview, setPreview] = useState(null);
const handleFileChange = async (e) => {
const file = e.target.files[0];
if (file) {
const cropper = new CropImagePro(file, "profile-picture", {
aspectRatio: 1,
maxOutputSize: 800,
});
try {
const result = await cropper.open();
setPreview(result.previewUrl);
// Upload to server
// await uploadImage(result.file);
} catch (error) {
console.log("Cancelled");
}
}
};
return (
<div>
<input type="file" accept="image/*,.heic" onChange={handleFileChange} />
{preview && <img src={preview} alt="Preview" />}
</div>
);
}
<template>
<div>
<input type="file" accept="image/*,.heic" @change="handleFileChange" />
<img v-if="preview" :src="preview" alt="Preview" />
</div>
</template>
<script setup>
import { ref } from "vue";
import CropImagePro from "crop-image-pro";
import "crop-image-pro/css";
const preview = ref(null);
const handleFileChange = async (e) => {
const file = e.target.files[0];
if (file) {
const cropper = new CropImagePro(file, "image", {
aspectRatio: 16 / 9,
});
try {
const result = await cropper.open();
preview.value = result.previewUrl;
} catch (error) {
console.log("Cancelled");
}
}
};
</script>
import { Component } from "@angular/core";
import CropImagePro from "crop-image-pro";
import "crop-image-pro/css";
@Component({
selector: "app-image-uploader",
template: `
<input
type="file"
accept="image/*,.heic"
(change)="handleFileChange($event)"
/>
<img *ngIf="preview" [src]="preview" alt="Preview" />
`,
})
export class ImageUploaderComponent {
preview: string | null = null;
async handleFileChange(event: Event) {
const input = event.target as HTMLInputElement;
const file = input.files?.[0];
if (file) {
const cropper = new CropImagePro(file, "image", {
aspectRatio: 1,
});
try {
const result = await cropper.open();
this.preview = result.previewUrl;
} catch (error) {
console.log("Cancelled");
}
}
}
}
new CropImagePro(file: File, fileName: string, options?: CropImageProOptions)
File (required) - The image file to cropstring (required) - Base name for the output fileCropImageProOptions (optional) - Configuration optionsinterface CropImageProOptions {
aspectRatio?: number; // Default: 1 (square)
maxOutputSize?: number; // Default: 1200 (pixels)
compressionQuality?: number; // Default: 0.7 (0-1)
circularCrop?: boolean; // Default: false
theme?: {
primaryColor?: string; // Default: '#073d44'
backgroundColor?: string; // Default: '#ffffff'
overlayColor?: string; // Default: 'rgba(0, 0, 0, 0.6)'
};
}
| Option | Type | Default | Description |
|---|---|---|---|
aspectRatio | number | 1 | Aspect ratio for crop (e.g., 1 for square, 16/9 for wide, 4/3 for portrait) |
maxOutputSize | number | 1200 | Maximum width or height of output image in pixels |
compressionQuality | number | 0.7 | JPEG compression quality (0-1, where 1 is highest quality) |
circularCrop | boolean | false | Show circular crop preview (only with aspectRatio 1) |
theme.primaryColor | string | '#073d44' | Primary color for UI elements |
theme.backgroundColor | string | '#ffffff' | Background color for modal |
theme.overlayColor | string | 'rgba(0, 0, 0, 0.6)' | Color for overlay backdrop |
open(): Promise<CropResult>Opens the crop editor modal and returns a promise that resolves with the crop result or rejects if cancelled.
Returns:
interface CropResult {
previewUrl: string; // Blob URL for preview
file: File; // Cropped image as File object
blob: Blob; // Cropped image as Blob
}
const cropper = new CropImagePro(file, "profile", {
aspectRatio: 1, // Square
maxOutputSize: 400, // Small size for profile pics
circularCrop: true, // Circular preview
compressionQuality: 0.8,
});
const cropper = new CropImagePro(file, "banner", {
aspectRatio: 16 / 9, // Wide format
maxOutputSize: 1920, // Full HD width
compressionQuality: 0.85,
});
const cropper = new CropImagePro(file, "product", {
aspectRatio: 4 / 3, // Standard photo ratio
maxOutputSize: 1200,
compressionQuality: 0.75,
});
const cropper = new CropImagePro(file, "image", {
aspectRatio: undefined, // User can choose any ratio
maxOutputSize: 2000,
});
// User can toggle aspect lock in the UI
The library automatically detects and converts HEIC/HEIF images (common on iOS devices) to JPEG format:
// Works automatically with HEIC files
const file = input.files[0]; // Could be .heic
const cropper = new CropImagePro(file, "photo");
const result = await cropper.open();
// result.file is JPEG
All output images are automatically compressed to balance quality and file size:
// High quality (larger file)
const cropper = new CropImagePro(file, "image", {
compressionQuality: 0.9,
});
// Balanced (default)
const cropper = new CropImagePro(file, "image", {
compressionQuality: 0.7,
});
// Smaller file size
const cropper = new CropImagePro(file, "image", {
compressionQuality: 0.5,
});
You can customize the appearance by overriding CSS variables or classes:
/* Custom theme colors */
.crop-image-pro-modal {
--primary-color: #your-color;
}
/* Or override specific classes */
.crop-image-pro-btn-primary {
background-color: #your-brand-color;
}
Full TypeScript definitions are included:
import CropImagePro, { CropImageProOptions, CropResult } from "crop-image-pro";
const options: CropImageProOptions = {
aspectRatio: 16 / 9,
maxOutputSize: 1920,
};
const cropper = new CropImagePro(file, "image", options);
const result: CropResult = await cropper.open();
try {
const cropper = new CropImagePro(file, "image");
const result = await cropper.open();
// Success - use result
await uploadImage(result.file);
} catch (error) {
if (error.message === "User cancelled") {
// User clicked cancel
console.log("User cancelled crop");
} else {
// Other errors (file loading, etc.)
console.error("Error:", error);
}
}
URL.revokeObjectURL(result.previewUrl) when done// Example with best practices
async function handleImageUpload(file) {
// Validate file type
if (!file.type.startsWith("image/")) {
alert("Please select an image file");
return;
}
// Validate file size (e.g., max 10MB)
if (file.size > 10 * 1024 * 1024) {
alert("File too large. Maximum 10MB");
return;
}
try {
const cropper = new CropImagePro(file, "image", {
maxOutputSize: 1200,
compressionQuality: 0.7,
});
const result = await cropper.open();
// Upload to server
await uploadToServer(result.file);
// Display preview
displayPreview(result.previewUrl);
// Clean up after some time
setTimeout(() => {
URL.revokeObjectURL(result.previewUrl);
}, 60000);
} catch (error) {
if (error.message !== "User cancelled") {
console.error("Upload failed:", error);
alert("Failed to process image");
}
}
}
See the examples directory for complete working examples:
MIT © Jeslor Ssozi
Contributions are welcome! Please feel free to submit a Pull Request.
Found a bug or have a feature request? Please open an issue on GitHub.
FAQs
Professional image cropping library with HEIC support, compression, and easy integration. Framework-agnostic vanilla JavaScript/TypeScript solution.
The npm package crop-image-pro receives a total of 65 weekly downloads. As such, crop-image-pro popularity was classified as not popular.
We found that crop-image-pro demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.