nicehero commited on
Commit
a2ecadc
·
1 Parent(s): 7c2d5c6

mask3.html

Browse files
Files changed (1) hide show
  1. mask3.html +774 -0
mask3.html ADDED
@@ -0,0 +1,774 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ --bg-color: var(--tg-theme-bg-color);
12
+ font: 12px/18px "Lucida Grande", "Lucida Sans Unicode", Arial, Helvetica, Verdana, sans-serif;
13
+ background-color: var(--bg-color);
14
+ color: var(--tg-theme-text-color);
15
+
16
+ width: 350;
17
+ margin: 0 auto; /* 水平居中 */
18
+ }
19
+ #canvas {
20
+ border: 1px solid #000;
21
+ width: 100%;
22
+ height: auto;
23
+ }
24
+ html, body {
25
+ overflow-x: hidden;
26
+ }
27
+ #uploadButton{
28
+ width: 80%;
29
+ }
30
+ #save{
31
+ width: 20%;
32
+ }
33
+ .myDiv {
34
+ width: 98%;
35
+ display: flex;
36
+ flex-direction: row;
37
+ justify-content: flex-start;
38
+ margin: 0px 1%;
39
+ flex-wrap: wrap;
40
+ }
41
+ .myDiv1 {
42
+ width: 98%;
43
+ display: flex;
44
+ flex-direction: row;
45
+ justify-content: flex-start;
46
+ margin: 0px 1%;
47
+ }
48
+ .overlay {
49
+ left: 20px;
50
+ }
51
+ }
52
+ /* 适用于电脑的样式 */
53
+ @media (min-width: 768px) {
54
+ #canvas {
55
+ border: 1px solid #000;
56
+ width: auto;
57
+ height: auto;
58
+ }
59
+ .myDiv {
60
+ display: flex;
61
+ flex-direction: row;
62
+ justify-content: center;
63
+ margin: 0 100px;
64
+ width: 512px;
65
+ flex-wrap: wrap;
66
+ }
67
+ .myDiv1 {
68
+ display: flex;
69
+ flex-direction: row;
70
+ justify-content: center;
71
+ margin: 0 100px;
72
+ width: 512px;
73
+ }
74
+ .overlay {
75
+ left: 100px;
76
+ }
77
+ }
78
+ #circle {
79
+ position: absolute;
80
+ width: 10px;
81
+ height: 10px;
82
+ border-radius: 50%;
83
+ border: 2px solid red;
84
+ background-color: transparent;
85
+ transition: opacity 1s;
86
+ pointer-events: none;
87
+ }
88
+ .show {
89
+ opacity: 1;
90
+ }
91
+ .hide {
92
+ opacity: 0;
93
+ }
94
+ .overlay {
95
+ position: absolute;
96
+ top: 82px;
97
+ z-index: 10;
98
+ /* 设置悬浮控件的样式和尺寸 */
99
+ /* 可以使用 z-index 属性来控制层叠顺序 */
100
+ }
101
+ </style>
102
+ </head>
103
+ <body>
104
+ <div class="myDiv1">
105
+ <button id="uploadButton" style="display: None;">
106
+ 选择图片
107
+ <input type="file" id="upload" accept="image/*" style="position: absolute; top: 0; left: 0; width: 98%; height: 100%; opacity: 0; cursor: pointer;">
108
+ </button>
109
+ <button id="save" style="height: 50px;display: None">保存蒙版</button>
110
+ <button id="saveToClipboard" style="height: 50px;box-sizing: border-box; padding: 10px; width: 98%; font-size: 16px; height: 50px;
111
+ line-height: 30px; overflow: hidden; position: relative;">上传蒙版 Upload mask</button>
112
+ </div>
113
+ <div class="myDiv" id="tools">
114
+ <input type="range" id="brushSizeSlider" style="width: 100%" value="40" min="1" max="150" step="1" >
115
+ </div>
116
+ <br>
117
+ <br>
118
+ <div class="myDiv" id="myImg1">
119
+ <canvas id="canvas"></canvas>
120
+ <br>
121
+ <img id="outputImg" ></img>
122
+ </div>
123
+ <div class="overlay" style="display: flex; flex-direction: row; align-items: flex-start;">
124
+ <label style="margin-bottom: 10px;">
125
+ <input type="radio" name="editMode" value="draw" checked> 画笔模式
126
+ </label>
127
+ <label style="margin-bottom: 10px;">
128
+ <input type="radio" name="editMode" value="erase"> 擦除模式
129
+ </label>
130
+ <label>
131
+ <input type="radio" name="editMode" value="select"> 不编辑
132
+ </label>
133
+ </div>
134
+ <div id="circle" style="width: 20px; height: 20px; border-radius: 50%; border: 2px solid red;"></div>
135
+ <!-- <script src="https://telegram.org/js/telegram-web-app.js"></script> -->
136
+ <script>
137
+ // Init TWA
138
+ //Telegram.WebApp.ready();
139
+ //Telegram.WebApp.expand();
140
+ //Telegram.WebApp.enableClosingConfirmation()
141
+ //Telegram.WebApp.HapticFeedback.impactOccurred("medium");
142
+ // Event occurs whenever theme settings are changed in the user's Telegram app (including switching to night mode).
143
+ //Telegram.WebApp.onEvent('themeChanged', function() {
144
+ // document.documentElement.className = Telegram.WebApp.colorScheme;
145
+ //});
146
+ function getQueryParameter(name) {
147
+ const urlParams = new URLSearchParams(window.location.search);
148
+ return urlParams.get(name);
149
+ }
150
+ async function uploadMask(base64String) {
151
+ const response = await fetch('https://api.imgur.com/3/image', {
152
+ method: 'POST',
153
+ headers: {
154
+ 'Authorization': 'Client-ID 955c061744537ff',
155
+ 'Content-Type': 'application/json',
156
+ },
157
+ body: JSON.stringify({ image: base64String }),
158
+ });
159
+ const r = await response.json()
160
+ return r.data.link;
161
+ }
162
+ window.onerror = function (message, source, lineno, colno, error) {
163
+ const errorData = {
164
+ message: message,
165
+ source: source,
166
+ lineno: lineno,
167
+ colno: colno,
168
+ stack: error ? error.stack : null
169
+ };
170
+ console.error("JavaScript Error:", errorData);
171
+ // 使用 Fetch API 上传错误信息
172
+ fetch('https://u7leyomozktm-5527.shanghai-01.dayunet.com/log-error', {
173
+ method: 'POST',
174
+ headers: {
175
+ 'Content-Type': 'application/json'
176
+ },
177
+ body: JSON.stringify(errorData)
178
+ });
179
+ };
180
+ window.onload = function() {
181
+ var canvas = document.getElementById('canvas');
182
+ var context = canvas.getContext('2d');
183
+ var image = document.getElementById('outputImg');
184
+ var imageMask = new Image();
185
+ var maskData = null;
186
+ var isDrawing = false;
187
+ var brushSize = 40;
188
+ var intervalHandel = null;
189
+ var brushSizeSlider = document.getElementById('brushSizeSlider');
190
+ var editModeRadios = document.getElementsByName('editMode');
191
+ var selectedMode = "draw";
192
+ var isRotate = false;
193
+ function isMobile() {
194
+ return (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent));
195
+ }
196
+ for (var i = 0; i < editModeRadios.length; i++) {
197
+ editModeRadios[i].addEventListener('change', function() {
198
+ // 获取选中的编辑模式值
199
+ selectedMode = this.value;
200
+ drawImagesInterval(100);
201
+ });
202
+ }
203
+ brushSizeSlider.addEventListener('input', function() {
204
+ brushSize = parseInt(this.value);
205
+ setCircleSize(brushSize);
206
+ if (isMobile()){
207
+ var canvasRect = canvas.getBoundingClientRect();
208
+ var scaleX = canvas.width / canvasRect.width;
209
+ showCircle(175 + window.scrollX, 200 + window.scrollY, scaleX);
210
+ }
211
+ });
212
+ function resizeImage(img,s,resizedImage) {
213
+ var maxWidth = s; // 最大宽度
214
+ var maxHeight = s; // 最大高度
215
+ var width = img.width;
216
+ var height = img.height;
217
+ if (width/height < 4/3 && width <= maxWidth && height <= maxHeight) {
218
+ return false;
219
+ }
220
+ if (!isMobile() && width <= maxWidth && height <= maxHeight) {
221
+ return false;
222
+ }
223
+ if (width > maxWidth || height > maxHeight || width/height >= 4/3) {
224
+ var ratio = Math.max(maxWidth / width, maxHeight / height);
225
+ if (width <= maxWidth && height <= maxHeight){
226
+ ratio = 1;
227
+ }
228
+ width = Math.floor(width * ratio);
229
+ height = Math.floor(height * ratio);
230
+ var tempCanvas = document.createElement('canvas');
231
+ tempCanvas.width = width;
232
+ tempCanvas.height = height;
233
+ var ctx = tempCanvas.getContext('2d');
234
+ isRotate = false;
235
+ if (width/height >= 4/3 && isMobile()){
236
+ tempCanvas.height = width;
237
+ tempCanvas.width = height;
238
+ ctx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
239
+ ctx.save();
240
+ ctx.translate(tempCanvas.width / 2, tempCanvas.height / 2);
241
+ ctx.rotate(Math.PI / 2);
242
+ ctx.drawImage(img, -img.width / 2, -img.height / 2);
243
+ ctx.restore();
244
+ isRotate = true;
245
+ }
246
+ else {
247
+ ctx.drawImage(img, 0, 0, width, height);
248
+ }
249
+ resizedImage.src = tempCanvas.toDataURL();
250
+ return true;
251
+ }
252
+ return false;
253
+ }
254
+
255
+ function drawImages() {
256
+ context.clearRect(0, 0, canvas.width, canvas.height);
257
+ context.putImageData(maskData,0,0);
258
+ if (selectedMode == "select") {
259
+ return;
260
+ }
261
+ context.globalAlpha = 0.75; // 设置透明度为0.5
262
+ context.drawImage(image, 0, 0);
263
+ //context.drawImage(imageMask, 0, 0);
264
+ context.globalAlpha = 1; // 恢复透明度为1
265
+ }
266
+ function drawImagesInterval(t) {
267
+ if (intervalHandel != null){
268
+ drawImagesTimeOut(100);
269
+ window.clearInterval(intervalHandel);
270
+ intervalHandel = null;
271
+ }
272
+ intervalHandel = window.setInterval(function() {drawImages();}, t);
273
+ }
274
+ window.addEventListener('scroll', function(event) {
275
+ var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
276
+ var overlay = document.querySelector(".overlay");
277
+ overlay.style.top = (scrollTop + 82) + "px";
278
+ });
279
+ function stopDrawImagesInterval() {
280
+ if (intervalHandel != null){
281
+ drawImagesTimeOut(100);
282
+ window.clearInterval(intervalHandel);
283
+ intervalHandel = null;
284
+ }
285
+ }
286
+ function drawImagesTimeOut(t) {
287
+ window.setTimeout(function() {drawImages();}, t);
288
+ }
289
+ function getImageDataB(img) {
290
+ context.clearRect(0, 0, canvas.width, canvas.height);
291
+ var width = image.width;
292
+ var height = image.height;
293
+ canvas.width = width;
294
+ canvas.height = height;
295
+ context.drawImage(img, 0, 0);
296
+ var imageData = context.getImageData(0, 0, width, height);
297
+ return imageData;
298
+ }
299
+ function getImageData(img) {
300
+ var tempCanvas = document.createElement('canvas');
301
+ tempCanvas.width = canvas.width;
302
+ tempCanvas.height = canvas.height;
303
+ var tempContext = tempCanvas.getContext('2d');
304
+ var width = image.width;
305
+ var height = image.height;
306
+ tempCanvas.width = width;
307
+ tempCanvas.height = height;
308
+ tempContext.drawImage(img, 0, 0);
309
+ var imageData = tempContext.getImageData(0, 0, width, height);
310
+ return imageData;
311
+ }
312
+ function createMaskImageData(width, height) {
313
+ // 创建一个新的ImageData对象
314
+ var imageData = new ImageData(width, height);
315
+ // 获取像素数据
316
+ var data = imageData.data;
317
+ // 将每个像素设置为黑色
318
+ for (var i = 0; i < data.length; i += 4) {
319
+ data[i] = 0; // 设置红色通道
320
+ data[i + 1] = 0; // 设置绿色通道
321
+ data[i + 2] = 0; // 设置蓝色通道
322
+ data[i + 3] = 255; // 设置透明度通道(不透明)
323
+ }
324
+ return imageData;
325
+ }
326
+ function getImageDataUrl(imageData) {
327
+ var tempCanvas = document.createElement('canvas');
328
+ tempCanvas.width = canvas.width;
329
+ tempCanvas.height = canvas.height;
330
+ var tempContext = tempCanvas.getContext('2d');
331
+ tempContext.putImageData(imageData, 0, 0);
332
+ return tempCanvas.toDataURL();
333
+ }
334
+ async function loadImageFromUrl0(imageUrl) {
335
+ const dataUrl = await convertImageUrlToDataUrl(imageUrl);
336
+ await loadImageFromUrl(dataUrl);
337
+ }
338
+ async function loadImageFromUrl(dataUrl) {
339
+ image.crossOrigin='anonymous';
340
+ image.onload = function() {
341
+ var resizedImage = new Image();
342
+ resizedImage.onload = _ok;
343
+ function _ok(event){
344
+ image = resizedImage;
345
+ canvas.width = resizedImage.width;
346
+ canvas.height = resizedImage.height;
347
+ maskData = createMaskImageData(image.width,image.height);
348
+ imageMask.src = getImageDataUrl(maskData);
349
+ drawImagesTimeOut(100);
350
+ }
351
+ if (!resizeImage(image,512,resizedImage)) {
352
+ canvas.width = image.width;
353
+ canvas.height = image.height;
354
+ maskData = createMaskImageData(image.width,image.height);
355
+ imageMask.src = getImageDataUrl(maskData);
356
+ drawImagesTimeOut(100);
357
+ }
358
+ }
359
+ image.src = dataUrl;
360
+ }
361
+ /*
362
+
363
+ function handleImageLoad(image) {
364
+ var resizedImage = new Image();
365
+ resizedImage.onload = function() {
366
+ image = resizedImage;
367
+ canvas.width = resizedImage.width;
368
+ canvas.height = resizedImage.height;
369
+ maskData = createMaskImageData(image.width, image.height);
370
+ imageMask.src = getImageDataUrl(maskData);
371
+ drawImagesTimeOut(100);
372
+ }
373
+
374
+ if (!resizeImage(image, 512, resizedImage)) {
375
+ canvas.width = image.width;
376
+ canvas.height = image.height;
377
+ maskData = createMaskImageData(image.width, image.height);
378
+ imageMask.src = getImageDataUrl(maskData);
379
+ drawImagesTimeOut(100);
380
+ }
381
+ }
382
+ // 监听文件选择
383
+ function handleFile(file) {
384
+ var reader = new FileReader();
385
+ reader.onload = function(event) {
386
+ var image = new Image();
387
+ image.onload = function() {
388
+ handleImageLoad(image);
389
+ }
390
+ image.src = event.target.result;
391
+ }
392
+ reader.readAsDataURL(file);
393
+ }
394
+ */
395
+ function handleFile(file) {
396
+ var reader = new FileReader();
397
+ reader.onload = function(event) {
398
+ image.onload = function() {
399
+ var resizedImage = new Image();
400
+ resizedImage.onload = _ok;
401
+ function _ok(event){
402
+ image = resizedImage;
403
+ canvas.width = resizedImage.width;
404
+ canvas.height = resizedImage.height;
405
+ maskData = createMaskImageData(image.width,image.height);
406
+ imageMask.src = getImageDataUrl(maskData);
407
+ drawImagesTimeOut(100);
408
+ }
409
+ if (!resizeImage(image,512,resizedImage)) {
410
+ canvas.width = image.width;
411
+ canvas.height = image.height;
412
+ maskData = createMaskImageData(image.width,image.height);
413
+ imageMask.src = getImageDataUrl(maskData);
414
+ drawImagesTimeOut(100);
415
+ }
416
+ }
417
+ image.src = event.target.result;
418
+ console.log(image.src);
419
+ }
420
+ reader.readAsDataURL(file);
421
+ }
422
+
423
+ // 上传图片
424
+ document.getElementById("upload").addEventListener('change', function(e) {
425
+ var file = e.target.files[0];
426
+ handleFile(file);
427
+ });
428
+
429
+ // 添加拖拽文件事件监听
430
+ document.addEventListener('dragover', function(e) {
431
+ e.preventDefault();
432
+ });
433
+ document.addEventListener('drop', function(e) {
434
+ e.preventDefault();
435
+ // 获取拖拽事件中的文件对象
436
+ var file = e.dataTransfer.files[0];
437
+ // 执行与文件上传按钮相同的操作
438
+ handleFile(file);
439
+ });
440
+
441
+ function inRect(x,y,rect){
442
+ return (
443
+ x >= rect.left &&
444
+ x <= rect.right &&
445
+ y >= rect.top &&
446
+ y <= rect.bottom
447
+ );
448
+ }
449
+ function calcCanvasOffset(e,canvas) {
450
+ var canvasRect = canvas.getBoundingClientRect();
451
+ var scaleX = canvas.width / canvasRect.width;
452
+ var scaleY = canvas.height / canvasRect.height;
453
+ var offsetX = (e.clientX - canvasRect.left) * scaleX;
454
+ var offsetY = (e.clientY - canvasRect.top) * scaleY;
455
+ return [offsetX,offsetY,scaleX,scaleY];
456
+ }
457
+ // 开始绘制
458
+ function onTouchDown(e) {
459
+ if (selectedMode == "select") {
460
+ return;
461
+ }
462
+ var canvasRect = canvas.getBoundingClientRect();
463
+ var [offsetX,offsetY,scaleX,scaleY] = calcCanvasOffset(e,canvas);
464
+ //console.log([offsetX,offsetY,scaleX,scaleY]);
465
+ if (!inRect(e.clientX,e.clientY,canvasRect)){
466
+ return;
467
+ }
468
+ if (draw(offsetX, offsetY)) {
469
+ isDrawing = true;
470
+ drawImagesInterval(100);
471
+ }
472
+ }
473
+ document.addEventListener('touchstart', function(event) {
474
+ var touch = event.touches[0];
475
+ onTouchDown(touch);
476
+ });
477
+ document.addEventListener('mousedown',function(event){
478
+ onTouchDown(event);
479
+ } );
480
+ // 结束绘制
481
+ document.addEventListener('mouseup', function() {
482
+ isDrawing = false;
483
+ stopDrawImagesInterval();
484
+ });
485
+ // 绘制中
486
+ function onMove(e) {
487
+ var [offsetX,offsetY,scaleX,scaleY] = calcCanvasOffset(e,canvas);
488
+ if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
489
+ showCircle(e.clientX + window.scrollX, e.clientY + window.scrollY, scaleX);
490
+ } else {
491
+ showCircle(e.clientX + window.scrollX, e.clientY + window.scrollY, scaleX);
492
+ }
493
+ var canvasRect = canvas.getBoundingClientRect();
494
+ if (isDrawing) {
495
+ //console.log('onMove1');
496
+ if (!inRect(e.clientX,e.clientY,canvasRect)){
497
+ return;
498
+ }
499
+ draw(offsetX, offsetY);
500
+ }
501
+ }
502
+ canvas.addEventListener('touchmove', function(event) {
503
+ if (selectedMode == "select") {
504
+ return;
505
+ }
506
+ event.preventDefault();
507
+ var touch = event.touches[0];
508
+ onMove(touch);
509
+ }, { passive: false });
510
+ if (!isMobile()) {
511
+ document.addEventListener('mousemove', function(event){
512
+ onMove(event);
513
+ });
514
+ }
515
+
516
+
517
+ // 绘制函数
518
+ function draw(x, y) {
519
+ if (selectedMode == "selected") {
520
+ return false;
521
+ }
522
+ if (maskData == null) {
523
+ return false;
524
+ }
525
+ var data = maskData.data;
526
+ var brushRadius = brushSize / 2;
527
+
528
+ for (var i = -brushRadius; i <= brushRadius; i++) {
529
+ for (var j = -brushRadius; j <= brushRadius; j++) {
530
+ var pixelX = Math.round(x + i);
531
+ var pixelY = Math.round(y + j);
532
+
533
+ if (pixelX < 0 || pixelX >= canvas.width || pixelY < 0 || pixelY >= canvas.height) {
534
+ continue;
535
+ }
536
+ var distance = Math.sqrt((pixelX - x) * (pixelX - x) + (pixelY - y) * (pixelY - y));
537
+ if (distance > brushRadius) {
538
+ continue;
539
+ }
540
+ var index = (pixelY * canvas.width + pixelX) * 4;
541
+ if (selectedMode == "draw"){
542
+ data[index] = 255; // 设置红色通道为最大值,即白色
543
+ data[index + 1] = 255; // 设置绿色通道为最大值,即白色
544
+ data[index + 2] = 255;
545
+ }
546
+ else {
547
+ data[index] = 0; // 设置红色通道为最大值,即白色
548
+ data[index + 1] = 0; // 设置绿色通道为最大值,即白色
549
+ data[index + 2] = 0;
550
+ }
551
+
552
+ //data[index + 3] = 128;
553
+ }
554
+ }
555
+ //imageMask.src = getImageDataUrl(maskData);
556
+ return true;
557
+ }
558
+ function generateRandomFileName() {
559
+ var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
560
+ var length = 10; // 文件名长度
561
+ var fileName = '';
562
+ for (var i = 0; i < length; i++) {
563
+ var randomIndex = Math.floor(Math.random() * characters.length);
564
+ fileName += characters.charAt(randomIndex);
565
+ }
566
+ return fileName;
567
+ }
568
+ function rotateImageData(imageData) {
569
+ const { width, height } = imageData;
570
+ const rotatedData = new Uint8ClampedArray(width * height * 4);
571
+
572
+ for (let y = 0; y < height; y++) {
573
+ for (let x = 0; x < width; x++) {
574
+ const srcIndex = (x + y * width) * 4;
575
+ const destIndex = ((width - x - 1) * height + y) * 4;
576
+
577
+ rotatedData[destIndex] = imageData.data[srcIndex];
578
+ rotatedData[destIndex + 1] = imageData.data[srcIndex + 1];
579
+ rotatedData[destIndex + 2] = imageData.data[srcIndex + 2];
580
+ rotatedData[destIndex + 3] = imageData.data[srcIndex + 3];
581
+ }
582
+ }
583
+
584
+ return new ImageData(rotatedData, height, width);
585
+ }
586
+
587
+ function openImageInNewTab(dataUrl) {
588
+ const newTab = window.open();
589
+ newTab.document.write('<html><body style="margin: 0;"><img src="' + dataUrl + '"></body></html>');
590
+ newTab.document.close();
591
+ }
592
+ function saveImageAsFile(dataUrl, filename) {
593
+ // 将 Data URL 转换为 Blob 对象
594
+ const blob = dataURLToBlob(dataUrl);
595
+
596
+ // 创建一个链接元素
597
+ const link = document.createElement('a');
598
+ link.href = URL.createObjectURL(blob);
599
+ link.download = filename;
600
+
601
+ // 模拟点击下载链接
602
+ link.click();
603
+
604
+ // 释放 URL 对象
605
+ URL.revokeObjectURL(link.href);
606
+ }
607
+
608
+ function dataURLToBlob(dataUrl) {
609
+ console.log(dataUrl);
610
+ const commaIndex = dataUrl.indexOf(',');
611
+ const mime = dataUrl.substring(5, commaIndex);
612
+ const base64Data = dataUrl.substring(commaIndex + 1);
613
+ const byteCharacters = atob(base64Data);
614
+ const byteNumbers = new Array(byteCharacters.length);
615
+
616
+ for (let i = 0; i < byteCharacters.length; i++) {
617
+ byteNumbers[i] = byteCharacters.charCodeAt(i);
618
+ }
619
+
620
+ const byteArray = new Uint8Array(byteNumbers);
621
+
622
+ return new Blob([byteArray], { type: mime });
623
+ }
624
+
625
+ document.getElementById('saveToClipboard').addEventListener('click',async function() {
626
+ var data = maskData.data;
627
+ var tempCanvas = document.createElement('canvas');
628
+ var ctx = tempCanvas.getContext('2d');
629
+ if (isRotate == true){
630
+ var rData = rotateImageData(maskData);
631
+ tempCanvas.height = maskData.width;
632
+ tempCanvas.width = maskData.height;
633
+ ctx.putImageData(rData, 0, 0);
634
+ }
635
+ else {
636
+ tempCanvas.width = canvas.width;
637
+ tempCanvas.height = canvas.height;
638
+ ctx.putImageData(maskData, 0, 0);
639
+ }
640
+ //await navigator.clipboard.writeText(tempCanvas.toDataURL("image/jpeg", 0.9));
641
+ const response = await fetch(tempCanvas.toDataURL("image/png"));
642
+ const blob = await response.blob();
643
+ const item = new ClipboardItem({ [blob.type]: blob });
644
+ await navigator.clipboard.write([item]);
645
+
646
+ const img = document.getElementById('outputImg');
647
+ img.src = tempCanvas.toDataURL("image/jpeg");
648
+ const base64String = img.src.split(',')[1];
649
+ const response2 = await fetch(
650
+ 'https://u7leyomozktm-5527.shanghai-01.dayunet.com/uploadVPMask/' + getQueryParameter('id'),{
651
+ //'https://api.imgur.com/3/image', {
652
+ method: 'POST',
653
+ headers: {
654
+ 'Authorization': 'Client-ID 955c061744537ff',
655
+ 'Content-Type': 'application/json',
656
+ },
657
+ body: JSON.stringify({ image: base64String }),
658
+ });
659
+ /*const r = await response2.json();
660
+ img.src = r.data.link;
661
+ //Telegram.WebApp.sendData("" + Telegram.WebApp.initDataUnsafe.user.id + ";" + r.data.link);
662
+ const script = document.createElement('script');
663
+ script.src = "https://telegram.org/js/telegram-widget.js?22";
664
+ script.setAttribute('data-telegram-share-url', r.data.link);
665
+ script.async = true;
666
+ */
667
+ const myImg1 = document.getElementById('myImg1');
668
+ const firstChild = myImg1.firstChild;
669
+ let sendback = document.createElement('a');
670
+ sendback.href = 'https://t.me/ainudevideo_bot?start=mask_ok';// + r.data.link;
671
+ sendback.textContent = 'sendback';
672
+ sendback.click();
673
+ sendback.innerHTML = "如果点击按钮没有反应,请点这个链接 If there is no response when clicking the button, please click on this link";
674
+ myImg1.insertBefore(sendback, firstChild);
675
+ //Telegram.WebApp.close();
676
+ });
677
+
678
+ // 保存蒙版
679
+ document.getElementById('save').addEventListener('click', function() {
680
+ var data = maskData.data;
681
+ var tempCanvas = document.createElement('canvas');
682
+ var ctx = tempCanvas.getContext('2d');
683
+ if (isRotate == true){
684
+ var rData = rotateImageData(maskData);
685
+ tempCanvas.height = maskData.width;
686
+ tempCanvas.width = maskData.height;
687
+ ctx.putImageData(rData, 0, 0);
688
+ }
689
+ else {
690
+ tempCanvas.width = canvas.width;
691
+ tempCanvas.height = canvas.height;
692
+ ctx.putImageData(maskData, 0, 0);
693
+ }
694
+ var link = document.createElement('a');
695
+ link.href = tempCanvas.toDataURL("image/jpeg", 0.9);
696
+ link.download = 'mask_' + generateRandomFileName() + '.jpg';
697
+ link.click();
698
+ var oldMode = selectedMode;
699
+ selectedMode = "select";
700
+ drawImages();
701
+ selectedMode = oldMode;
702
+ //saveImageAsFile(tempCanvas.toDataURL("image/jpeg", 0.9),'mask_' + generateRandomFileName() + '.jpg');
703
+ //openImageInNewTab(tempCanvas.toDataURL("image/jpeg", 0.9));
704
+ });
705
+ // 获取圆圈元素
706
+ var circle = document.getElementById('circle');
707
+
708
+ // 根据 brushSize 设置圆圈大小
709
+ function setCircleSize(brushSize) {
710
+ }
711
+
712
+ // 在屏幕上显示圆圈
713
+ function showCircle(x, y, scale) {
714
+ circle.style.left = (x - brushSize/scale/2) + 'px';
715
+ circle.style.top = (y - brushSize/scale/2) + 'px';
716
+ circle.style.width = (brushSize / scale) + 'px';
717
+ circle.style.height = (brushSize / scale) + 'px';
718
+ circle.classList.add('show');
719
+ circle.classList.remove('hide');
720
+
721
+ // 过一秒后隐藏圆圈
722
+ setTimeout(hideCircle, 1000);
723
+ }
724
+
725
+ // 隐藏圆圈
726
+ function hideCircle() {
727
+ circle.classList.remove('show');
728
+ circle.classList.add('hide');
729
+ }
730
+
731
+ // 手机平台点击事件处理函数
732
+ function handleTouchStart(e) {
733
+ // 只处理单指触摸事件
734
+ if (e.touches.length === 1) {
735
+ var touch = e.touches[0];
736
+ var x = touch.clientX;
737
+ var y = touch.clientY;
738
+ var [offsetX,offsetY,scaleX,scaleY] = calcCanvasOffset(touch,canvas);
739
+ // 在屏幕上显示圆圈
740
+ showCircle(x + window.scrollX, y + window.scrollY, scaleX);
741
+ }
742
+ }
743
+ async function convertImageUrlToDataUrl(imageUrl) {
744
+ const response = await fetch(imageUrl);
745
+ const blob = await response.blob();
746
+ return new Promise((resolve, reject) => {
747
+ const reader = new FileReader();
748
+ reader.onloadend = () => resolve(reader.result);
749
+ reader.onerror = (error) => reject(`Error reading blob: ${error}`);
750
+ reader.readAsDataURL(blob);
751
+ });
752
+ }
753
+
754
+ // 初始化圆圈大小
755
+ setCircleSize(brushSize);
756
+ hideCircle();
757
+ // 设置事件监听
758
+ //setEventListeners();
759
+ //const imageUrl = getQueryParameter('imageUrl');
760
+ //const imageUrl = 'https://i.imgur.com/' + Telegram.WebApp.initDataUnsafe.user.id + '.jpeg';
761
+ //const imageUrl = 'https://u7leyomozktm-5527.shanghai-01.dayunet.com/getVPImage/' + Telegram.WebApp.initDataUnsafe.user.id;
762
+ const imageUrl = 'https://u7leyomozktm-5527.shanghai-01.dayunet.com/getVPImage/' + getQueryParameter('id');
763
+ if (imageUrl) {
764
+ loadImageFromUrl(imageUrl);
765
+ }
766
+
767
+
768
+ }
769
+ </script>
770
+ <!-- Eruda is console for mobile browsers -->
771
+ <!-- <script src="https://cdn.jsdelivr.net/npm/eruda"></script> -->
772
+ <!-- <script>eruda.init();</script> -->
773
+ </body>
774
+ </html>