nicehero commited on
Commit
9f92875
·
verified ·
1 Parent(s): 56ca385

Upload index.html

Browse files
Files changed (1) hide show
  1. index.html +576 -525
index.html CHANGED
@@ -1,526 +1,577 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
5
- <title>蒙版王</title>
6
- <style>
7
- /* 适用于手机的样式 */
8
- @media (max-width: 767px) {
9
- body {
10
- width: 350;
11
- margin: 0 auto; /* 水平居中 */
12
- }
13
- #canvas {
14
- border: 1px solid #000;
15
- width: 100%;
16
- height: auto;
17
- }
18
- html, body {
19
- overflow-x: hidden;
20
- }
21
- #uploadButton{
22
- width: 80%;
23
- }
24
- #save{
25
- width: 20%;
26
- }
27
- .myDiv {
28
- width: 98%;
29
- display: flex;
30
- flex-direction: row;
31
- justify-content: flex-start;
32
- margin: 0px 1%;
33
- }
34
- .overlay {
35
- left: 20px;
36
- }
37
- }
38
- /* 适用于电脑的样式 */
39
- @media (min-width: 768px) {
40
- #canvas {
41
- border: 1px solid #000;
42
- width: auto;
43
- height: auto;
44
- }
45
- .myDiv {
46
- display: flex;
47
- flex-direction: row;
48
- justify-content: center;
49
- margin: 0 100px;
50
- width: 512px;
51
- }
52
- .overlay {
53
- left: 100px;
54
- }
55
- }
56
- #circle {
57
- position: absolute;
58
- width: 10px;
59
- height: 10px;
60
- border-radius: 50%;
61
- border: 2px solid red;
62
- background-color: transparent;
63
- transition: opacity 1s;
64
- pointer-events: none;
65
- }
66
- .show {
67
- opacity: 1;
68
- }
69
- .hide {
70
- opacity: 0;
71
- }
72
- .overlay {
73
- position: absolute;
74
- top: 82px;
75
- z-index: 10;
76
- /* 设置悬浮控件的样式和尺寸 */
77
- /* 可以使用 z-index 属性来制层叠顺序 */
78
- }
79
- </style>
80
- </head>
81
- <body>
82
- <div class="myDiv">
83
- <button id="uploadButton" style="box-sizing: border-box; padding: 10px; font-size: 16px; height: 50px; line-height: 30px; overflow: hidden; position: relative;">
84
- 选择图片
85
- <input type="file" id="upload" accept="image/*" style="position: absolute; top: 0; left: 0; width: 98%; height: 100%; opacity: 0; cursor: pointer;">
86
- </button>
87
- <button id="save" style="height: 50px;">保存蒙版</button>
88
- </div>
89
- <div class="myDiv">
90
- <input type="range" id="brushSizeSlider" style="width: 100%" value="40" min="1" max="150" step="1" >
91
- </div>
92
- <br>
93
- <br>
94
- <div class="myDiv">
95
- <canvas id="canvas"></canvas>
96
- </div>
97
- <div class="overlay" style="display: flex; flex-direction: row; align-items: flex-start;">
98
- <label style="margin-bottom: 10px;">
99
- <input type="radio" name="editMode" value="draw" checked> 画笔模式
100
- </label>
101
- <label style="margin-bottom: 10px;">
102
- <input type="radio" name="editMode" value="erase"> 擦除模式
103
- </label>
104
- <label>
105
- <input type="radio" name="editMode" value="select"> 不编辑
106
- </label>
107
- </div>
108
- <div id="circle" style="width: 20px; height: 20px; border-radius: 50%; border: 2px solid red;"></div>
109
- <script>
110
- window.onload = function() {
111
- var canvas = document.getElementById('canvas');
112
- var context = canvas.getContext('2d');
113
- var image = new Image();
114
- var imageMask = new Image();
115
- var maskData = null;
116
- var isDrawing = false;
117
- var brushSize = 40;
118
- var intervalHandel = null;
119
- var brushSizeSlider = document.getElementById('brushSizeSlider');
120
- var editModeRadios = document.getElementsByName('editMode');
121
- var selectedMode = "draw";
122
- var isRotate = false;
123
- function isMobile() {
124
- return (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent));
125
- }
126
- for (var i = 0; i < editModeRadios.length; i++) {
127
- editModeRadios[i].addEventListener('change', function() {
128
- // 获取选中的编辑模式值
129
- selectedMode = this.value;
130
- drawImagesInterval(100);
131
- });
132
- }
133
- brushSizeSlider.addEventListener('input', function() {
134
- brushSize = parseInt(this.value);
135
- setCircleSize(brushSize);
136
- if (isMobile()){
137
- var canvasRect = canvas.getBoundingClientRect();
138
- var scaleX = canvas.width / canvasRect.width;
139
- showCircle(175 + window.scrollX, 200 + window.scrollY, scaleX);
140
- }
141
- });
142
- function resizeImage(img,s,resizedImage) {
143
- var maxWidth = s; // 最大宽度
144
- var maxHeight = s; // 最大高度
145
- var width = img.width;
146
- var height = img.height;
147
- if (width/height < 4/3 && width <= maxWidth && height <= maxHeight) {
148
- return false;
149
- }
150
- if (!isMobile() && width <= maxWidth && height <= maxHeight) {
151
- return false;
152
- }
153
- if (width > maxWidth || height > maxHeight || width/height >= 4/3) {
154
- var ratio = Math.max(maxWidth / width, maxHeight / height);
155
- if (width <= maxWidth && height <= maxHeight){
156
- ratio = 1;
157
- }
158
- width = Math.floor(width * ratio);
159
- height = Math.floor(height * ratio);
160
- var tempCanvas = document.createElement('canvas');
161
- tempCanvas.width = width;
162
- tempCanvas.height = height;
163
- var ctx = tempCanvas.getContext('2d');
164
- isRotate = false;
165
- if (width/height >= 4/3 && isMobile()){
166
- tempCanvas.height = width;
167
- tempCanvas.width = height;
168
- ctx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
169
- ctx.save();
170
- ctx.translate(tempCanvas.width / 2, tempCanvas.height / 2);
171
- ctx.rotate(Math.PI / 2);
172
- ctx.drawImage(img, -img.width / 2, -img.height / 2);
173
- ctx.restore();
174
- isRotate = true;
175
- }
176
- else {
177
- ctx.drawImage(img, 0, 0, width, height);
178
- }
179
- resizedImage.src = tempCanvas.toDataURL();
180
- return true;
181
- }
182
- return false;
183
- }
184
-
185
- function drawImages() {
186
- context.clearRect(0, 0, canvas.width, canvas.height);
187
- context.putImageData(maskData,0,0);
188
- if (selectedMode == "select") {
189
- return;
190
- }
191
- context.globalAlpha = 0.75; // 设置透明度为0.5
192
- context.drawImage(image, 0, 0);
193
- //context.drawImage(imageMask, 0, 0);
194
- context.globalAlpha = 1; // 恢复透明度为1
195
- }
196
- function drawImagesInterval(t) {
197
- if (intervalHandel != null){
198
- drawImagesTimeOut(100);
199
- window.clearInterval(intervalHandel);
200
- intervalHandel = null;
201
- }
202
- intervalHandel = window.setInterval(function() {drawImages();}, t);
203
- }
204
- window.addEventListener('scroll', function(event) {
205
- var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
206
- var overlay = document.querySelector(".overlay");
207
- overlay.style.top = (scrollTop + 82) + "px";
208
- });
209
- function stopDrawImagesInterval() {
210
- if (intervalHandel != null){
211
- drawImagesTimeOut(100);
212
- window.clearInterval(intervalHandel);
213
- intervalHandel = null;
214
- }
215
- }
216
- function drawImagesTimeOut(t) {
217
- window.setTimeout(function() {drawImages();}, t);
218
- }
219
- function getImageDataB(img) {
220
- context.clearRect(0, 0, canvas.width, canvas.height);
221
- var width = image.width;
222
- var height = image.height;
223
- canvas.width = width;
224
- canvas.height = height;
225
- context.drawImage(img, 0, 0);
226
- var imageData = context.getImageData(0, 0, width, height);
227
- return imageData;
228
- }
229
- function getImageData(img) {
230
- var tempCanvas = document.createElement('canvas');
231
- tempCanvas.width = canvas.width;
232
- tempCanvas.height = canvas.height;
233
- var tempContext = tempCanvas.getContext('2d');
234
- var width = image.width;
235
- var height = image.height;
236
- tempCanvas.width = width;
237
- tempCanvas.height = height;
238
- tempContext.drawImage(img, 0, 0);
239
- var imageData = tempContext.getImageData(0, 0, width, height);
240
- return imageData;
241
- }
242
- function createMaskImageData(width, height) {
243
- // 创建一个新的ImageData对象
244
- var imageData = new ImageData(width, height);
245
- // 获取像素数据
246
- var data = imageData.data;
247
- // 将每个像素设置为黑色
248
- for (var i = 0; i < data.length; i += 4) {
249
- data[i] = 0; // 设置红色通道
250
- data[i + 1] = 0; // 设置绿色通道
251
- data[i + 2] = 0; // 设置蓝色通道
252
- data[i + 3] = 255; // 设置透明度通道(不透明)
253
- }
254
- return imageData;
255
- }
256
- function getImageDataUrl(imageData) {
257
- var tempCanvas = document.createElement('canvas');
258
- tempCanvas.width = canvas.width;
259
- tempCanvas.height = canvas.height;
260
- var tempContext = tempCanvas.getContext('2d');
261
- tempContext.putImageData(imageData, 0, 0);
262
- return tempCanvas.toDataURL();
263
- }
264
- function handleFile(file) {
265
- var reader = new FileReader();
266
- reader.onload = function(event) {
267
- image.onload = function() {
268
- var resizedImage = new Image();
269
- resizedImage.onload = _ok;
270
- function _ok(event){
271
- image = resizedImage;
272
- canvas.width = resizedImage.width;
273
- canvas.height = resizedImage.height;
274
- maskData = createMaskImageData(image.width,image.height);
275
- imageMask.src = getImageDataUrl(maskData);
276
- drawImagesTimeOut(100);
277
- }
278
- if (!resizeImage(image,512,resizedImage)) {
279
- canvas.width = image.width;
280
- canvas.height = image.height;
281
- maskData = createMaskImageData(image.width,image.height);
282
- imageMask.src = getImageDataUrl(maskData);
283
- drawImagesTimeOut(100);
284
- }
285
- }
286
- image.src = event.target.result;
287
- }
288
- reader.readAsDataURL(file);
289
- }
290
- // 上传图片
291
- document.getElementById("upload").addEventListener('change', function(e) {
292
- var file = e.target.files[0];
293
- handleFile(file);
294
- });
295
-
296
- // 添加拖拽文件事件监听
297
- document.addEventListener('dragover', function(e) {
298
- e.preventDefault();
299
- });
300
- document.addEventListener('drop', function(e) {
301
- e.preventDefault();
302
- // 获取拖拽事件中的文件对象
303
- var file = e.dataTransfer.files[0];
304
- // 执行与文件上传按钮相同的操作
305
- handleFile(file);
306
- });
307
-
308
- function inRect(x,y,rect){
309
- return (
310
- x >= rect.left &&
311
- x <= rect.right &&
312
- y >= rect.top &&
313
- y <= rect.bottom
314
- );
315
- }
316
- function calcCanvasOffset(e,canvas) {
317
- var canvasRect = canvas.getBoundingClientRect();
318
- var scaleX = canvas.width / canvasRect.width;
319
- var scaleY = canvas.height / canvasRect.height;
320
- var offsetX = (e.clientX - canvasRect.left) * scaleX;
321
- var offsetY = (e.clientY - canvasRect.top) * scaleY;
322
- return [offsetX,offsetY,scaleX,scaleY];
323
- }
324
- // 开始绘制
325
- function onTouchDown(e) {
326
- if (selectedMode == "select") {
327
- return;
328
- }
329
- var canvasRect = canvas.getBoundingClientRect();
330
- var [offsetX,offsetY,scaleX,scaleY] = calcCanvasOffset(e,canvas);
331
- //console.log([offsetX,offsetY,scaleX,scaleY]);
332
- if (!inRect(e.clientX,e.clientY,canvasRect)){
333
- return;
334
- }
335
- if (draw(offsetX, offsetY)) {
336
- isDrawing = true;
337
- drawImagesInterval(100);
338
- }
339
- }
340
- document.addEventListener('touchstart', function(event) {
341
- var touch = event.touches[0];
342
- onTouchDown(touch);
343
- });
344
- document.addEventListener('mousedown',function(event){
345
- onTouchDown(event);
346
- } );
347
- // 结束绘制
348
- document.addEventListener('mouseup', function() {
349
- isDrawing = false;
350
- stopDrawImagesInterval();
351
- });
352
- // 绘制中
353
- function onMove(e) {
354
- var [offsetX,offsetY,scaleX,scaleY] = calcCanvasOffset(e,canvas);
355
- if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
356
- showCircle(e.clientX + window.scrollX, e.clientY + window.scrollY, scaleX);
357
- } else {
358
- showCircle(e.clientX + window.scrollX, e.clientY + window.scrollY, scaleX);
359
- }
360
- var canvasRect = canvas.getBoundingClientRect();
361
- if (isDrawing) {
362
- //console.log('onMove1');
363
- if (!inRect(e.clientX,e.clientY,canvasRect)){
364
- return;
365
- }
366
- draw(offsetX, offsetY);
367
- }
368
- }
369
- canvas.addEventListener('touchmove', function(event) {
370
- if (selectedMode == "select") {
371
- return;
372
- }
373
- event.preventDefault();
374
- var touch = event.touches[0];
375
- onMove(touch);
376
- }, { passive: false });
377
- if (!isMobile()) {
378
- document.addEventListener('mousemove', function(event){
379
- onMove(event);
380
- });
381
- }
382
-
383
-
384
- // 绘制函数
385
- function draw(x, y) {
386
- if (selectedMode == "selected") {
387
- return false;
388
- }
389
- if (maskData == null) {
390
- return false;
391
- }
392
- var data = maskData.data;
393
- var brushRadius = brushSize / 2;
394
-
395
- for (var i = -brushRadius; i <= brushRadius; i++) {
396
- for (var j = -brushRadius; j <= brushRadius; j++) {
397
- var pixelX = Math.round(x + i);
398
- var pixelY = Math.round(y + j);
399
-
400
- if (pixelX < 0 || pixelX >= canvas.width || pixelY < 0 || pixelY >= canvas.height) {
401
- continue;
402
- }
403
- var distance = Math.sqrt((pixelX - x) * (pixelX - x) + (pixelY - y) * (pixelY - y));
404
- if (distance > brushRadius) {
405
- continue;
406
- }
407
- var index = (pixelY * canvas.width + pixelX) * 4;
408
- if (selectedMode == "draw"){
409
- data[index] = 255; // 设置红色通道为最大值,即白色
410
- data[index + 1] = 255; // 设置绿色通道为最大值,即白色
411
- data[index + 2] = 255;
412
- }
413
- else {
414
- data[index] = 0; // 设置红色通道为最大值,即白色
415
- data[index + 1] = 0; // 设置绿色通道为最大值,即白色
416
- data[index + 2] = 0;
417
- }
418
-
419
- //data[index + 3] = 128;
420
- }
421
- }
422
- //imageMask.src = getImageDataUrl(maskData);
423
- return true;
424
- }
425
- function generateRandomFileName() {
426
- var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
427
- var length = 10; // 文件名长度
428
- var fileName = '';
429
- for (var i = 0; i < length; i++) {
430
- var randomIndex = Math.floor(Math.random() * characters.length);
431
- fileName += characters.charAt(randomIndex);
432
- }
433
- return fileName;
434
- }
435
- function rotateImageData(imageData) {
436
- const { width, height } = imageData;
437
- const rotatedData = new Uint8ClampedArray(width * height * 4);
438
-
439
- for (let y = 0; y < height; y++) {
440
- for (let x = 0; x < width; x++) {
441
- const srcIndex = (x + y * width) * 4;
442
- const destIndex = ((width - x - 1) * height + y) * 4;
443
-
444
- rotatedData[destIndex] = imageData.data[srcIndex];
445
- rotatedData[destIndex + 1] = imageData.data[srcIndex + 1];
446
- rotatedData[destIndex + 2] = imageData.data[srcIndex + 2];
447
- rotatedData[destIndex + 3] = imageData.data[srcIndex + 3];
448
- }
449
- }
450
-
451
- return new ImageData(rotatedData, height, width);
452
- }
453
- // 保存蒙版
454
- document.getElementById('save').addEventListener('click', function() {
455
- var data = maskData.data;
456
- var tempCanvas = document.createElement('canvas');
457
- var ctx = tempCanvas.getContext('2d');
458
- if (isRotate == true){
459
- var rData = rotateImageData(maskData);
460
- tempCanvas.height = maskData.width;
461
- tempCanvas.width = maskData.height;
462
- ctx.putImageData(rData, 0, 0);
463
- }
464
- else {
465
- tempCanvas.width = canvas.width;
466
- tempCanvas.height = canvas.height;
467
- ctx.putImageData(maskData, 0, 0);
468
- }
469
- var link = document.createElement('a');
470
- link.href = tempCanvas.toDataURL("image/jpeg", 0.9);
471
- link.download = 'mask_' + generateRandomFileName() + '.jpg';
472
- link.click();
473
- var oldMode = selectedMode;
474
- selectedMode = "select";
475
- drawImages();
476
- selectedMode = oldMode;
477
- });
478
- // 获取圆圈元素
479
- var circle = document.getElementById('circle');
480
-
481
- // 根据 brushSize 设置圆圈大小
482
- function setCircleSize(brushSize) {
483
- }
484
-
485
- // 在屏幕上显示圆圈
486
- function showCircle(x, y, scale) {
487
- circle.style.left = (x - brushSize/scale/2) + 'px';
488
- circle.style.top = (y - brushSize/scale/2) + 'px';
489
- circle.style.width = (brushSize / scale) + 'px';
490
- circle.style.height = (brushSize / scale) + 'px';
491
- circle.classList.add('show');
492
- circle.classList.remove('hide');
493
-
494
- // 过一秒后隐藏圆圈
495
- setTimeout(hideCircle, 1000);
496
- }
497
-
498
- // 隐藏圆圈
499
- function hideCircle() {
500
- circle.classList.remove('show');
501
- circle.classList.add('hide');
502
- }
503
-
504
- // 手机平台点击事件处理函数
505
- function handleTouchStart(e) {
506
- // 只处理单指触摸事件
507
- if (e.touches.length === 1) {
508
- var touch = e.touches[0];
509
- var x = touch.clientX;
510
- var y = touch.clientY;
511
- var [offsetX,offsetY,scaleX,scaleY] = calcCanvasOffset(touch,canvas);
512
- // 在屏幕上显示圆圈
513
- showCircle(x + window.scrollX, y + window.scrollY, scaleX);
514
- }
515
- }
516
-
517
-
518
- // 初始化圆圈大小
519
- setCircleSize(brushSize);
520
- hideCircle();
521
- // 设置事件监听
522
- //setEventListeners();
523
- }
524
- </script>
525
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
526
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
6
+ <title>蒙版王</title>
7
+ <style>
8
+ /* 适用于手机的样式 */
9
+ @media (max-width: 767px) {
10
+ body {
11
+ width: 350;
12
+ margin: 0 auto; /* 水平居中 */
13
+ }
14
+ #canvas {
15
+ border: 1px solid #000;
16
+ width: 100%;
17
+ height: auto;
18
+ }
19
+ html, body {
20
+ overflow-x: hidden;
21
+ }
22
+ #uploadButton{
23
+ width: 80%;
24
+ }
25
+ #save{
26
+ width: 20%;
27
+ }
28
+ .myDiv {
29
+ width: 98%;
30
+ display: flex;
31
+ flex-direction: row;
32
+ justify-content: flex-start;
33
+ margin: 0px 1%;
34
+ }
35
+ .overlay {
36
+ left: 20px;
37
+ }
38
+ }
39
+ /* 适用于电脑的样式 */
40
+ @media (min-width: 768px) {
41
+ #canvas {
42
+ border: 1px solid #000;
43
+ width: auto;
44
+ height: auto;
45
+ }
46
+ .myDiv {
47
+ display: flex;
48
+ flex-direction: row;
49
+ justify-content: center;
50
+ margin: 0 100px;
51
+ width: 512px;
52
+ }
53
+ .overlay {
54
+ left: 100px;
55
+ }
56
+ }
57
+ #circle {
58
+ position: absolute;
59
+ width: 10px;
60
+ height: 10px;
61
+ border-radius: 50%;
62
+ border: 2px solid red;
63
+ background-color: transparent;
64
+ transition: opacity 1s;
65
+ pointer-events: none;
66
+ }
67
+ .show {
68
+ opacity: 1;
69
+ }
70
+ .hide {
71
+ opacity: 0;
72
+ }
73
+ .overlay {
74
+ position: absolute;
75
+ top: 82px;
76
+ z-index: 10;
77
+ /* 设置悬浮件的样式和尺寸 */
78
+ /* 可以使用 z-index 属性来控制层叠顺序 */
79
+ }
80
+ </style>
81
+ </head>
82
+ <body>
83
+ <div class="myDiv">
84
+ <button id="uploadButton" style="box-sizing: border-box; padding: 10px; font-size: 16px; height: 50px; line-height: 30px; overflow: hidden; position: relative;">
85
+ 选择图片
86
+ <input type="file" id="upload" accept="image/*" style="position: absolute; top: 0; left: 0; width: 98%; height: 100%; opacity: 0; cursor: pointer;">
87
+ </button>
88
+ <button id="save" style="height: 50px;">保存蒙版</button>
89
+ </div>
90
+ <div class="myDiv">
91
+ <input type="range" id="brushSizeSlider" style="width: 100%" value="40" min="1" max="150" step="1" >
92
+ </div>
93
+ <br>
94
+ <br>
95
+ <div class="myDiv">
96
+ <canvas id="canvas"></canvas>
97
+ </div>
98
+ <div class="overlay" style="display: flex; flex-direction: row; align-items: flex-start;">
99
+ <label style="margin-bottom: 10px;">
100
+ <input type="radio" name="editMode" value="draw" checked> 画笔模式
101
+ </label>
102
+ <label style="margin-bottom: 10px;">
103
+ <input type="radio" name="editMode" value="erase"> 擦除模式
104
+ </label>
105
+ <label>
106
+ <input type="radio" name="editMode" value="select"> 不编辑
107
+ </label>
108
+ </div>
109
+ <div id="circle" style="width: 20px; height: 20px; border-radius: 50%; border: 2px solid red;"></div>
110
+ <script src="https://telegram.org/js/telegram-web-app.js"></script>
111
+ <script>
112
+ // Init TWA
113
+ Telegram.WebApp.ready();
114
+ Telegram.WebApp.expand();
115
+ Telegram.WebApp.enableClosingConfirmation()
116
+ Telegram.WebApp.HapticFeedback.impactOccurred("medium");
117
+ // Event occurs whenever theme settings are changed in the user's Telegram app (including switching to night mode).
118
+ Telegram.WebApp.onEvent('themeChanged', function() {
119
+ document.documentElement.className = Telegram.WebApp.colorScheme;
120
+ });
121
+ window.onload = function() {
122
+ var canvas = document.getElementById('canvas');
123
+ var context = canvas.getContext('2d');
124
+ var image = new Image();
125
+ var imageMask = new Image();
126
+ var maskData = null;
127
+ var isDrawing = false;
128
+ var brushSize = 40;
129
+ var intervalHandel = null;
130
+ var brushSizeSlider = document.getElementById('brushSizeSlider');
131
+ var editModeRadios = document.getElementsByName('editMode');
132
+ var selectedMode = "draw";
133
+ var isRotate = false;
134
+ function isMobile() {
135
+ return (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent));
136
+ }
137
+ for (var i = 0; i < editModeRadios.length; i++) {
138
+ editModeRadios[i].addEventListener('change', function() {
139
+ // 获取选中的编辑模式值
140
+ selectedMode = this.value;
141
+ drawImagesInterval(100);
142
+ });
143
+ }
144
+ brushSizeSlider.addEventListener('input', function() {
145
+ brushSize = parseInt(this.value);
146
+ setCircleSize(brushSize);
147
+ if (isMobile()){
148
+ var canvasRect = canvas.getBoundingClientRect();
149
+ var scaleX = canvas.width / canvasRect.width;
150
+ showCircle(175 + window.scrollX, 200 + window.scrollY, scaleX);
151
+ }
152
+ });
153
+ function resizeImage(img,s,resizedImage) {
154
+ var maxWidth = s; // 最大宽度
155
+ var maxHeight = s; // 最大高度
156
+ var width = img.width;
157
+ var height = img.height;
158
+ if (width/height < 4/3 && width <= maxWidth && height <= maxHeight) {
159
+ return false;
160
+ }
161
+ if (!isMobile() && width <= maxWidth && height <= maxHeight) {
162
+ return false;
163
+ }
164
+ if (width > maxWidth || height > maxHeight || width/height >= 4/3) {
165
+ var ratio = Math.max(maxWidth / width, maxHeight / height);
166
+ if (width <= maxWidth && height <= maxHeight){
167
+ ratio = 1;
168
+ }
169
+ width = Math.floor(width * ratio);
170
+ height = Math.floor(height * ratio);
171
+ var tempCanvas = document.createElement('canvas');
172
+ tempCanvas.width = width;
173
+ tempCanvas.height = height;
174
+ var ctx = tempCanvas.getContext('2d');
175
+ isRotate = false;
176
+ if (width/height >= 4/3 && isMobile()){
177
+ tempCanvas.height = width;
178
+ tempCanvas.width = height;
179
+ ctx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
180
+ ctx.save();
181
+ ctx.translate(tempCanvas.width / 2, tempCanvas.height / 2);
182
+ ctx.rotate(Math.PI / 2);
183
+ ctx.drawImage(img, -img.width / 2, -img.height / 2);
184
+ ctx.restore();
185
+ isRotate = true;
186
+ }
187
+ else {
188
+ ctx.drawImage(img, 0, 0, width, height);
189
+ }
190
+ resizedImage.src = tempCanvas.toDataURL();
191
+ return true;
192
+ }
193
+ return false;
194
+ }
195
+
196
+ function drawImages() {
197
+ context.clearRect(0, 0, canvas.width, canvas.height);
198
+ context.putImageData(maskData,0,0);
199
+ if (selectedMode == "select") {
200
+ return;
201
+ }
202
+ context.globalAlpha = 0.75; // 设置透明度为0.5
203
+ context.drawImage(image, 0, 0);
204
+ //context.drawImage(imageMask, 0, 0);
205
+ context.globalAlpha = 1; // 恢复透明度为1
206
+ }
207
+ function drawImagesInterval(t) {
208
+ if (intervalHandel != null){
209
+ drawImagesTimeOut(100);
210
+ window.clearInterval(intervalHandel);
211
+ intervalHandel = null;
212
+ }
213
+ intervalHandel = window.setInterval(function() {drawImages();}, t);
214
+ }
215
+ window.addEventListener('scroll', function(event) {
216
+ var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
217
+ var overlay = document.querySelector(".overlay");
218
+ overlay.style.top = (scrollTop + 82) + "px";
219
+ });
220
+ function stopDrawImagesInterval() {
221
+ if (intervalHandel != null){
222
+ drawImagesTimeOut(100);
223
+ window.clearInterval(intervalHandel);
224
+ intervalHandel = null;
225
+ }
226
+ }
227
+ function drawImagesTimeOut(t) {
228
+ window.setTimeout(function() {drawImages();}, t);
229
+ }
230
+ function getImageDataB(img) {
231
+ context.clearRect(0, 0, canvas.width, canvas.height);
232
+ var width = image.width;
233
+ var height = image.height;
234
+ canvas.width = width;
235
+ canvas.height = height;
236
+ context.drawImage(img, 0, 0);
237
+ var imageData = context.getImageData(0, 0, width, height);
238
+ return imageData;
239
+ }
240
+ function getImageData(img) {
241
+ var tempCanvas = document.createElement('canvas');
242
+ tempCanvas.width = canvas.width;
243
+ tempCanvas.height = canvas.height;
244
+ var tempContext = tempCanvas.getContext('2d');
245
+ var width = image.width;
246
+ var height = image.height;
247
+ tempCanvas.width = width;
248
+ tempCanvas.height = height;
249
+ tempContext.drawImage(img, 0, 0);
250
+ var imageData = tempContext.getImageData(0, 0, width, height);
251
+ return imageData;
252
+ }
253
+ function createMaskImageData(width, height) {
254
+ // 创建一个新的ImageData对象
255
+ var imageData = new ImageData(width, height);
256
+ // 获取像素数据
257
+ var data = imageData.data;
258
+ // 将每个像素设置为黑色
259
+ for (var i = 0; i < data.length; i += 4) {
260
+ data[i] = 0; // 设置红色通道
261
+ data[i + 1] = 0; // 设置绿色通道
262
+ data[i + 2] = 0; // 设置蓝色通道
263
+ data[i + 3] = 255; // 设置透明度通道(不透明)
264
+ }
265
+ return imageData;
266
+ }
267
+ function getImageDataUrl(imageData) {
268
+ var tempCanvas = document.createElement('canvas');
269
+ tempCanvas.width = canvas.width;
270
+ tempCanvas.height = canvas.height;
271
+ var tempContext = tempCanvas.getContext('2d');
272
+ tempContext.putImageData(imageData, 0, 0);
273
+ return tempCanvas.toDataURL();
274
+ }
275
+ function handleFile(file) {
276
+ var reader = new FileReader();
277
+ reader.onload = function(event) {
278
+ image.onload = function() {
279
+ var resizedImage = new Image();
280
+ resizedImage.onload = _ok;
281
+ function _ok(event){
282
+ image = resizedImage;
283
+ canvas.width = resizedImage.width;
284
+ canvas.height = resizedImage.height;
285
+ maskData = createMaskImageData(image.width,image.height);
286
+ imageMask.src = getImageDataUrl(maskData);
287
+ drawImagesTimeOut(100);
288
+ }
289
+ if (!resizeImage(image,512,resizedImage)) {
290
+ canvas.width = image.width;
291
+ canvas.height = image.height;
292
+ maskData = createMaskImageData(image.width,image.height);
293
+ imageMask.src = getImageDataUrl(maskData);
294
+ drawImagesTimeOut(100);
295
+ }
296
+ }
297
+ image.src = event.target.result;
298
+ }
299
+ reader.readAsDataURL(file);
300
+ }
301
+ // 上传图片
302
+ document.getElementById("upload").addEventListener('change', function(e) {
303
+ var file = e.target.files[0];
304
+ handleFile(file);
305
+ });
306
+
307
+ // 添加拖拽文件事件监听
308
+ document.addEventListener('dragover', function(e) {
309
+ e.preventDefault();
310
+ });
311
+ document.addEventListener('drop', function(e) {
312
+ e.preventDefault();
313
+ // 获取拖拽事件中的文件对象
314
+ var file = e.dataTransfer.files[0];
315
+ // 执行与文件上传按钮相同的操作
316
+ handleFile(file);
317
+ });
318
+
319
+ function inRect(x,y,rect){
320
+ return (
321
+ x >= rect.left &&
322
+ x <= rect.right &&
323
+ y >= rect.top &&
324
+ y <= rect.bottom
325
+ );
326
+ }
327
+ function calcCanvasOffset(e,canvas) {
328
+ var canvasRect = canvas.getBoundingClientRect();
329
+ var scaleX = canvas.width / canvasRect.width;
330
+ var scaleY = canvas.height / canvasRect.height;
331
+ var offsetX = (e.clientX - canvasRect.left) * scaleX;
332
+ var offsetY = (e.clientY - canvasRect.top) * scaleY;
333
+ return [offsetX,offsetY,scaleX,scaleY];
334
+ }
335
+ // 开始绘制
336
+ function onTouchDown(e) {
337
+ if (selectedMode == "select") {
338
+ return;
339
+ }
340
+ var canvasRect = canvas.getBoundingClientRect();
341
+ var [offsetX,offsetY,scaleX,scaleY] = calcCanvasOffset(e,canvas);
342
+ //console.log([offsetX,offsetY,scaleX,scaleY]);
343
+ if (!inRect(e.clientX,e.clientY,canvasRect)){
344
+ return;
345
+ }
346
+ if (draw(offsetX, offsetY)) {
347
+ isDrawing = true;
348
+ drawImagesInterval(100);
349
+ }
350
+ }
351
+ document.addEventListener('touchstart', function(event) {
352
+ var touch = event.touches[0];
353
+ onTouchDown(touch);
354
+ });
355
+ document.addEventListener('mousedown',function(event){
356
+ onTouchDown(event);
357
+ } );
358
+ // 结束绘制
359
+ document.addEventListener('mouseup', function() {
360
+ isDrawing = false;
361
+ stopDrawImagesInterval();
362
+ });
363
+ // 绘制中
364
+ function onMove(e) {
365
+ var [offsetX,offsetY,scaleX,scaleY] = calcCanvasOffset(e,canvas);
366
+ if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
367
+ showCircle(e.clientX + window.scrollX, e.clientY + window.scrollY, scaleX);
368
+ } else {
369
+ showCircle(e.clientX + window.scrollX, e.clientY + window.scrollY, scaleX);
370
+ }
371
+ var canvasRect = canvas.getBoundingClientRect();
372
+ if (isDrawing) {
373
+ //console.log('onMove1');
374
+ if (!inRect(e.clientX,e.clientY,canvasRect)){
375
+ return;
376
+ }
377
+ draw(offsetX, offsetY);
378
+ }
379
+ }
380
+ canvas.addEventListener('touchmove', function(event) {
381
+ if (selectedMode == "select") {
382
+ return;
383
+ }
384
+ event.preventDefault();
385
+ var touch = event.touches[0];
386
+ onMove(touch);
387
+ }, { passive: false });
388
+ if (!isMobile()) {
389
+ document.addEventListener('mousemove', function(event){
390
+ onMove(event);
391
+ });
392
+ }
393
+
394
+
395
+ // 绘制函数
396
+ function draw(x, y) {
397
+ if (selectedMode == "selected") {
398
+ return false;
399
+ }
400
+ if (maskData == null) {
401
+ return false;
402
+ }
403
+ var data = maskData.data;
404
+ var brushRadius = brushSize / 2;
405
+
406
+ for (var i = -brushRadius; i <= brushRadius; i++) {
407
+ for (var j = -brushRadius; j <= brushRadius; j++) {
408
+ var pixelX = Math.round(x + i);
409
+ var pixelY = Math.round(y + j);
410
+
411
+ if (pixelX < 0 || pixelX >= canvas.width || pixelY < 0 || pixelY >= canvas.height) {
412
+ continue;
413
+ }
414
+ var distance = Math.sqrt((pixelX - x) * (pixelX - x) + (pixelY - y) * (pixelY - y));
415
+ if (distance > brushRadius) {
416
+ continue;
417
+ }
418
+ var index = (pixelY * canvas.width + pixelX) * 4;
419
+ if (selectedMode == "draw"){
420
+ data[index] = 255; // 设置红色通道为最大值,即白色
421
+ data[index + 1] = 255; // 设置绿色通道为最大值,即白色
422
+ data[index + 2] = 255;
423
+ }
424
+ else {
425
+ data[index] = 0; // 设置红色通道为最大值,即白色
426
+ data[index + 1] = 0; // 设置绿色通道为最大值,即白色
427
+ data[index + 2] = 0;
428
+ }
429
+
430
+ //data[index + 3] = 128;
431
+ }
432
+ }
433
+ //imageMask.src = getImageDataUrl(maskData);
434
+ return true;
435
+ }
436
+ function generateRandomFileName() {
437
+ var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
438
+ var length = 10; // 文件名长度
439
+ var fileName = '';
440
+ for (var i = 0; i < length; i++) {
441
+ var randomIndex = Math.floor(Math.random() * characters.length);
442
+ fileName += characters.charAt(randomIndex);
443
+ }
444
+ return fileName;
445
+ }
446
+ function rotateImageData(imageData) {
447
+ const { width, height } = imageData;
448
+ const rotatedData = new Uint8ClampedArray(width * height * 4);
449
+
450
+ for (let y = 0; y < height; y++) {
451
+ for (let x = 0; x < width; x++) {
452
+ const srcIndex = (x + y * width) * 4;
453
+ const destIndex = ((width - x - 1) * height + y) * 4;
454
+
455
+ rotatedData[destIndex] = imageData.data[srcIndex];
456
+ rotatedData[destIndex + 1] = imageData.data[srcIndex + 1];
457
+ rotatedData[destIndex + 2] = imageData.data[srcIndex + 2];
458
+ rotatedData[destIndex + 3] = imageData.data[srcIndex + 3];
459
+ }
460
+ }
461
+
462
+ return new ImageData(rotatedData, height, width);
463
+ }
464
+
465
+ function openImageInNewTab(dataUrl) {
466
+ const newTab = window.open();
467
+ newTab.document.write('<html><body style="margin: 0;"><img src="' + dataUrl + '"></body></html>');
468
+ newTab.document.close();
469
+ }
470
+ function saveImageAsFile(dataUrl, filename) {
471
+ // Data URL 转换为 Blob 对象
472
+ const blob = dataURLToBlob(dataUrl);
473
+
474
+ // 创建一个链接元素
475
+ const link = document.createElement('a');
476
+ link.href = URL.createObjectURL(blob);
477
+ link.download = filename;
478
+
479
+ // 模拟点击下载链接
480
+ link.click();
481
+
482
+ // 释放 URL 对象
483
+ URL.revokeObjectURL(link.href);
484
+ }
485
+
486
+ function dataURLToBlob(dataUrl) {
487
+ console.log(dataUrl);
488
+ const commaIndex = dataUrl.indexOf(',');
489
+ const mime = dataUrl.substring(5, commaIndex);
490
+ const base64Data = dataUrl.substring(commaIndex + 1);
491
+ const byteCharacters = atob(base64Data);
492
+ const byteNumbers = new Array(byteCharacters.length);
493
+
494
+ for (let i = 0; i < byteCharacters.length; i++) {
495
+ byteNumbers[i] = byteCharacters.charCodeAt(i);
496
+ }
497
+
498
+ const byteArray = new Uint8Array(byteNumbers);
499
+
500
+ return new Blob([byteArray], { type: mime });
501
+ }
502
+ // 保存蒙版
503
+ document.getElementById('save').addEventListener('click', function() {
504
+ var data = maskData.data;
505
+ var tempCanvas = document.createElement('canvas');
506
+ var ctx = tempCanvas.getContext('2d');
507
+ if (isRotate == true){
508
+ var rData = rotateImageData(maskData);
509
+ tempCanvas.height = maskData.width;
510
+ tempCanvas.width = maskData.height;
511
+ ctx.putImageData(rData, 0, 0);
512
+ }
513
+ else {
514
+ tempCanvas.width = canvas.width;
515
+ tempCanvas.height = canvas.height;
516
+ ctx.putImageData(maskData, 0, 0);
517
+ }
518
+ var link = document.createElement('a');
519
+ link.href = tempCanvas.toDataURL("image/jpeg", 0.9);
520
+ link.download = 'mask_' + generateRandomFileName() + '.jpg';
521
+ link.click();
522
+ var oldMode = selectedMode;
523
+ selectedMode = "select";
524
+ drawImages();
525
+ selectedMode = oldMode;
526
+ //saveImageAsFile(tempCanvas.toDataURL("image/jpeg", 0.9),'mask_' + generateRandomFileName() + '.jpg');
527
+ //openImageInNewTab(tempCanvas.toDataURL("image/jpeg", 0.9));
528
+ });
529
+ // 获取圆圈元素
530
+ var circle = document.getElementById('circle');
531
+
532
+ // 根据 brushSize 设置圆圈大小
533
+ function setCircleSize(brushSize) {
534
+ }
535
+
536
+ // 在屏幕上显示圆圈
537
+ function showCircle(x, y, scale) {
538
+ circle.style.left = (x - brushSize/scale/2) + 'px';
539
+ circle.style.top = (y - brushSize/scale/2) + 'px';
540
+ circle.style.width = (brushSize / scale) + 'px';
541
+ circle.style.height = (brushSize / scale) + 'px';
542
+ circle.classList.add('show');
543
+ circle.classList.remove('hide');
544
+
545
+ // 过一秒后隐藏圆圈
546
+ setTimeout(hideCircle, 1000);
547
+ }
548
+
549
+ // 隐藏圆圈
550
+ function hideCircle() {
551
+ circle.classList.remove('show');
552
+ circle.classList.add('hide');
553
+ }
554
+
555
+ // 手机平台点击事件处理函数
556
+ function handleTouchStart(e) {
557
+ // 只处理单指触摸事件
558
+ if (e.touches.length === 1) {
559
+ var touch = e.touches[0];
560
+ var x = touch.clientX;
561
+ var y = touch.clientY;
562
+ var [offsetX,offsetY,scaleX,scaleY] = calcCanvasOffset(touch,canvas);
563
+ // 在屏幕上显示圆圈
564
+ showCircle(x + window.scrollX, y + window.scrollY, scaleX);
565
+ }
566
+ }
567
+
568
+
569
+ // 初始化圆圈大小
570
+ setCircleSize(brushSize);
571
+ hideCircle();
572
+ // 设置事件监听
573
+ //setEventListeners();
574
+ }
575
+ </script>
576
+ </body>
577
  </html>