Skip to content

Commit d117432

Browse files
authored
1 parent 41ce0b8 commit d117432

File tree

1 file changed

+196
-0
lines changed

1 file changed

+196
-0
lines changed

bbox-cropper.html

+196
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>BBox Tool - CropperJS Version</title>
5+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.6.1/cropper.min.css">
6+
<style>
7+
.container {
8+
max-width: 1200px;
9+
margin: 20px auto;
10+
padding: 20px;
11+
font-family: system-ui, -apple-system, sans-serif;
12+
}
13+
14+
.image-container {
15+
position: relative;
16+
display: inline-block;
17+
margin: 20px 0;
18+
border: 2px dashed #ccc;
19+
min-width: 320px;
20+
min-height: 240px;
21+
cursor: crosshair;
22+
}
23+
24+
.image-container.dragover {
25+
border-color: #4CAF50;
26+
background: rgba(76, 175, 80, 0.1);
27+
}
28+
29+
#targetImage {
30+
max-width: 100%;
31+
display: block;
32+
}
33+
34+
.output {
35+
font-family: monospace;
36+
margin-top: 10px;
37+
padding: 10px;
38+
background: #f5f5f5;
39+
border-radius: 4px;
40+
}
41+
42+
.instructions {
43+
margin: 20px 0;
44+
padding: 15px;
45+
background: #f8f9fa;
46+
border-radius: 4px;
47+
line-height: 1.5;
48+
}
49+
50+
/* Hide default aspect ratio boxes that CropperJS shows */
51+
.cropper-view-box {
52+
outline: none !important;
53+
}
54+
55+
/* Customize the crop box appearance */
56+
.cropper-crop-box {
57+
background: rgba(76, 175, 80, 0.1) !important;
58+
}
59+
60+
.cropper-line, .cropper-point {
61+
background-color: #4CAF50 !important;
62+
}
63+
64+
.cropper-point {
65+
width: 10px !important;
66+
height: 10px !important;
67+
opacity: 1 !important;
68+
}
69+
70+
.cropper-point.point-n,
71+
.cropper-point.point-s,
72+
.cropper-point.point-e,
73+
.cropper-point.point-w {
74+
width: 10px !important;
75+
height: 10px !important;
76+
}
77+
</style>
78+
</head>
79+
<body>
80+
<div class="container">
81+
<h2>Bounding Box Drawing Tool (CropperJS)</h2>
82+
83+
<div class="instructions">
84+
<p><strong>Instructions:</strong></p>
85+
<ul>
86+
<li>Paste an image (Ctrl+V/Cmd+V), drag & drop, or click to select a file</li>
87+
<li>Click and drag to create a bounding box</li>
88+
<li>Drag the corners or edges to resize</li>
89+
<li>Drag inside the box to move it</li>
90+
<li>Coordinates are in percentages of image dimensions</li>
91+
</ul>
92+
</div>
93+
94+
<div id="imageContainer" class="image-container">
95+
<img id="targetImage" style="max-width: 100%;">
96+
<input type="file" id="fileInput" style="display: none" accept="image/*">
97+
</div>
98+
99+
<div class="output">
100+
<code>--box '<span id="bboxOutput">0,0,0,0</span>'</code>
101+
</div>
102+
</div>
103+
104+
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.6.1/cropper.min.js"></script>
105+
<script>
106+
const container = document.getElementById('imageContainer');
107+
const img = document.getElementById('targetImage');
108+
const fileInput = document.getElementById('fileInput');
109+
const output = document.getElementById('bboxOutput');
110+
let cropper = null;
111+
112+
// Handle image upload via click
113+
container.addEventListener('click', () => {
114+
if (!img.src) fileInput.click();
115+
});
116+
117+
fileInput.addEventListener('change', (e) => {
118+
const file = e.target.files[0];
119+
if (file) loadImage(file);
120+
});
121+
122+
// Handle drag and drop
123+
container.addEventListener('dragover', (e) => {
124+
e.preventDefault();
125+
container.classList.add('dragover');
126+
});
127+
128+
container.addEventListener('dragleave', () => {
129+
container.classList.remove('dragover');
130+
});
131+
132+
container.addEventListener('drop', (e) => {
133+
e.preventDefault();
134+
container.classList.remove('dragover');
135+
const file = e.dataTransfer.files[0];
136+
if (file && file.type.startsWith('image/')) {
137+
loadImage(file);
138+
}
139+
});
140+
141+
// Handle paste
142+
document.addEventListener('paste', (e) => {
143+
const items = e.clipboardData.items;
144+
for (let item of items) {
145+
if (item.type.startsWith('image/')) {
146+
const file = item.getAsFile();
147+
loadImage(file);
148+
break;
149+
}
150+
}
151+
});
152+
153+
function loadImage(file) {
154+
const reader = new FileReader();
155+
reader.onload = (e) => {
156+
img.src = e.target.result;
157+
img.style.display = 'block';
158+
159+
// Destroy existing cropper if it exists
160+
if (cropper) {
161+
cropper.destroy();
162+
}
163+
164+
// Initialize Cropper.js
165+
cropper = new Cropper(img, {
166+
viewMode: 1,
167+
dragMode: 'crop',
168+
autoCrop: true,
169+
movable: true,
170+
scalable: false,
171+
zoomable: false,
172+
rotatable: false,
173+
cropBoxResizable: true,
174+
cropBoxMovable: true,
175+
background: false,
176+
toggleDragModeOnDblclick: false,
177+
crop: updateOutput
178+
});
179+
};
180+
reader.readAsDataURL(file);
181+
}
182+
183+
function updateOutput(e) {
184+
const imageData = cropper.getImageData();
185+
186+
// Calculate percentages
187+
const x1 = Math.round((e.detail.x / imageData.naturalWidth) * 100);
188+
const y1 = Math.round((e.detail.y / imageData.naturalHeight) * 100);
189+
const x2 = Math.round(((e.detail.x + e.detail.width) / imageData.naturalWidth) * 100);
190+
const y2 = Math.round(((e.detail.y + e.detail.height) / imageData.naturalHeight) * 100);
191+
192+
output.textContent = `${x1},${y1},${x2},${y2}`;
193+
}
194+
</script>
195+
</body>
196+
</html>

0 commit comments

Comments
 (0)