| 1365 | } |
| 1366 | |
| 1367 | _applyHalftone(data, width, height, params) { |
| 1368 | const dotSize = params.dotSize; |
| 1369 | const angle = (params.angle * Math.PI) / 180; |
| 1370 | const cos = Math.cos(angle); |
| 1371 | const sin = Math.sin(angle); |
| 1372 | |
| 1373 | const output = new Uint8ClampedArray(data.length); |
| 1374 | output.fill(255); |
| 1375 | |
| 1376 | for (let y = 0; y < height; y++) { |
| 1377 | for (let x = 0; x < width; x++) { |
| 1378 | const rx = cos * x - sin * y; |
| 1379 | const ry = sin * x + cos * y; |
| 1380 | |
| 1381 | const cellX = Math.floor(rx / dotSize) * dotSize + dotSize / 2; |
| 1382 | const cellY = Math.floor(ry / dotSize) * dotSize + dotSize / 2; |
| 1383 | |
| 1384 | const dist = Math.sqrt(Math.pow(rx - cellX, 2) + Math.pow(ry - cellY, 2)); |
| 1385 | const origX = Math.round(cos * cellX + sin * cellY); |
| 1386 | const origY = Math.round(-sin * cellX + cos * cellY); |
| 1387 | const idx = (Math.max(0, Math.min(height - 1, origY)) * width + Math.max(0, Math.min(width - 1, origX))) * 4; |
| 1388 | |
| 1389 | const brightness = (data[idx] * 0.299 + data[idx + 1] * 0.587 + data[idx + 2] * 0.114) / 255; |
| 1390 | const radius = dotSize * 0.5 * Math.sqrt(brightness); |
| 1391 | |
| 1392 | const i = (y * width + x) * 4; |
| 1393 | if (dist < radius) { |
| 1394 | if (params.monochrome) { |
| 1395 | output[i] = output[i + 1] = output[i + 2] = 0; |
| 1396 | } else { |
| 1397 | output[i] = data[idx]; |
| 1398 | output[i + 1] = data[idx + 1]; |
| 1399 | output[i + 2] = data[idx + 2]; |
| 1400 | } |
| 1401 | } |
| 1402 | output[i + 3] = 255; |
| 1403 | } |
| 1404 | } |
| 1405 | |
| 1406 | for (let i = 0; i < data.length; i++) { |
| 1407 | data[i] = output[i]; |
| 1408 | } |
| 1409 | } |
| 1410 | |
| 1411 | _applyAscii(width, height, params) { |
| 1412 | const cellSize = params.cellSize; |