* Apply a luminance (brightness/contrast) effect to an image. * * OOXML ` ` supports `bright` (additive brightness offset, 0–100000 = 0–100%) * and `contrast` (multiplicative contrast, -100000 to 100000). * e.g. bright="100000" makes the entire image white (preserving alpha).
(lum: SafeXmlNode, img: HTMLImageElement)
| 560 | * e.g. bright="100000" makes the entire image white (preserving alpha). |
| 561 | */ |
| 562 | function applyLumEffect(lum: SafeXmlNode, img: HTMLImageElement): void { |
| 563 | const bright = (lum.numAttr('bright') ?? 0) / 100000 // 0–1 |
| 564 | const contrast = (lum.numAttr('contrast') ?? 0) / 100000 // -1 to 1 |
| 565 | |
| 566 | if (bright === 0 && contrast === 0) return |
| 567 | |
| 568 | const apply = () => { |
| 569 | const w = img.naturalWidth |
| 570 | const h = img.naturalHeight |
| 571 | if (!w || !h) return |
| 572 | |
| 573 | const canvas = document.createElement('canvas') |
| 574 | canvas.width = w |
| 575 | canvas.height = h |
| 576 | const c = canvas.getContext('2d') |
| 577 | if (!c) return |
| 578 | |
| 579 | c.drawImage(img, 0, 0) |
| 580 | const imageData = c.getImageData(0, 0, w, h) |
| 581 | const data = imageData.data |
| 582 | |
| 583 | for (let i = 0; i < data.length; i += 4) { |
| 584 | for (let ch = 0; ch < 3; ch++) { |
| 585 | // Normalize to 0–1 |
| 586 | let v = data[i + ch] / 255 |
| 587 | // Apply contrast (expand/compress around 0.5) |
| 588 | if (contrast !== 0) { |
| 589 | v = 0.5 + (v - 0.5) * (1 + contrast) |
| 590 | } |
| 591 | // Apply additive brightness offset |
| 592 | v += bright |
| 593 | data[i + ch] = Math.round(Math.max(0, Math.min(255, v * 255))) |
| 594 | } |
| 595 | // Alpha preserved |
| 596 | } |
| 597 | |
| 598 | c.putImageData(imageData, 0, 0) |
| 599 | img.src = canvas.toDataURL() |
| 600 | } |
| 601 | |
| 602 | if (img.complete && img.naturalWidth) { |
| 603 | apply() |
| 604 | } else { |
| 605 | img.addEventListener('load', apply, { once: true }) |
| 606 | } |
| 607 | } |
| 608 | |
| 609 | // --------------------------------------------------------------------------- |
| 610 | // BiLevel Effect |
no test coverage detected