@flighthq/bitmap 0.3.0-edge.1458.0c01b63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bitmap.d.ts +17 -0
- package/dist/bitmap.d.ts.map +1 -0
- package/dist/bitmap.js +87 -0
- package/dist/bitmap.js.map +1 -0
- package/dist/bitmapAffine.d.ts +27 -0
- package/dist/bitmapAffine.d.ts.map +1 -0
- package/dist/bitmapAffine.js +159 -0
- package/dist/bitmapAffine.js.map +1 -0
- package/dist/bitmapAlpha.d.ts +27 -0
- package/dist/bitmapAlpha.d.ts.map +1 -0
- package/dist/bitmapAlpha.js +83 -0
- package/dist/bitmapAlpha.js.map +1 -0
- package/dist/bitmapBevel.d.ts +24 -0
- package/dist/bitmapBevel.d.ts.map +1 -0
- package/dist/bitmapBevel.js +102 -0
- package/dist/bitmapBevel.js.map +1 -0
- package/dist/bitmapBlur.d.ts +57 -0
- package/dist/bitmapBlur.d.ts.map +1 -0
- package/dist/bitmapBlur.js +263 -0
- package/dist/bitmapBlur.js.map +1 -0
- package/dist/bitmapChannel.d.ts +24 -0
- package/dist/bitmapChannel.d.ts.map +1 -0
- package/dist/bitmapChannel.js +127 -0
- package/dist/bitmapChannel.js.map +1 -0
- package/dist/bitmapColorMatrix.d.ts +57 -0
- package/dist/bitmapColorMatrix.d.ts.map +1 -0
- package/dist/bitmapColorMatrix.js +127 -0
- package/dist/bitmapColorMatrix.js.map +1 -0
- package/dist/bitmapCompare.d.ts +18 -0
- package/dist/bitmapCompare.d.ts.map +1 -0
- package/dist/bitmapCompare.js +64 -0
- package/dist/bitmapCompare.js.map +1 -0
- package/dist/bitmapComposite.d.ts +54 -0
- package/dist/bitmapComposite.d.ts.map +1 -0
- package/dist/bitmapComposite.js +262 -0
- package/dist/bitmapComposite.js.map +1 -0
- package/dist/bitmapConvolution.d.ts +17 -0
- package/dist/bitmapConvolution.d.ts.map +1 -0
- package/dist/bitmapConvolution.js +103 -0
- package/dist/bitmapConvolution.js.map +1 -0
- package/dist/bitmapCopy.d.ts +23 -0
- package/dist/bitmapCopy.d.ts.map +1 -0
- package/dist/bitmapCopy.js +78 -0
- package/dist/bitmapCopy.js.map +1 -0
- package/dist/bitmapCoverage.d.ts +11 -0
- package/dist/bitmapCoverage.d.ts.map +1 -0
- package/dist/bitmapCoverage.js +29 -0
- package/dist/bitmapCoverage.js.map +1 -0
- package/dist/bitmapCrop.d.ts +33 -0
- package/dist/bitmapCrop.d.ts.map +1 -0
- package/dist/bitmapCrop.js +175 -0
- package/dist/bitmapCrop.js.map +1 -0
- package/dist/bitmapDisplacement.d.ts +22 -0
- package/dist/bitmapDisplacement.d.ts.map +1 -0
- package/dist/bitmapDisplacement.js +111 -0
- package/dist/bitmapDisplacement.js.map +1 -0
- package/dist/bitmapDissolve.d.ts +21 -0
- package/dist/bitmapDissolve.d.ts.map +1 -0
- package/dist/bitmapDissolve.js +97 -0
- package/dist/bitmapDissolve.js.map +1 -0
- package/dist/bitmapDraw.d.ts +8 -0
- package/dist/bitmapDraw.d.ts.map +1 -0
- package/dist/bitmapDraw.js +14 -0
- package/dist/bitmapDraw.js.map +1 -0
- package/dist/bitmapEncode.d.ts +3 -0
- package/dist/bitmapEncode.d.ts.map +1 -0
- package/dist/bitmapEncode.js +18 -0
- package/dist/bitmapEncode.js.map +1 -0
- package/dist/bitmapFill.d.ts +12 -0
- package/dist/bitmapFill.d.ts.map +1 -0
- package/dist/bitmapFill.js +85 -0
- package/dist/bitmapFill.js.map +1 -0
- package/dist/bitmapFingerprint.d.ts +26 -0
- package/dist/bitmapFingerprint.d.ts.map +1 -0
- package/dist/bitmapFingerprint.js +99 -0
- package/dist/bitmapFingerprint.js.map +1 -0
- package/dist/bitmapFlip.d.ts +16 -0
- package/dist/bitmapFlip.d.ts.map +1 -0
- package/dist/bitmapFlip.js +98 -0
- package/dist/bitmapFlip.js.map +1 -0
- package/dist/bitmapFormat.d.ts +26 -0
- package/dist/bitmapFormat.d.ts.map +1 -0
- package/dist/bitmapFormat.js +80 -0
- package/dist/bitmapFormat.js.map +1 -0
- package/dist/bitmapFrom.d.ts +23 -0
- package/dist/bitmapFrom.d.ts.map +1 -0
- package/dist/bitmapFrom.js +90 -0
- package/dist/bitmapFrom.js.map +1 -0
- package/dist/bitmapGradient.d.ts +36 -0
- package/dist/bitmapGradient.d.ts.map +1 -0
- package/dist/bitmapGradient.js +176 -0
- package/dist/bitmapGradient.js.map +1 -0
- package/dist/bitmapGradientFill.d.ts +32 -0
- package/dist/bitmapGradientFill.d.ts.map +1 -0
- package/dist/bitmapGradientFill.js +120 -0
- package/dist/bitmapGradientFill.js.map +1 -0
- package/dist/bitmapHistogram.d.ts +20 -0
- package/dist/bitmapHistogram.d.ts.map +1 -0
- package/dist/bitmapHistogram.js +61 -0
- package/dist/bitmapHistogram.js.map +1 -0
- package/dist/bitmapImageChannel.d.ts +2 -0
- package/dist/bitmapImageChannel.d.ts.map +1 -0
- package/dist/bitmapImageChannel.js +2 -0
- package/dist/bitmapImageChannel.js.map +1 -0
- package/dist/bitmapMedian.d.ts +14 -0
- package/dist/bitmapMedian.d.ts.map +1 -0
- package/dist/bitmapMedian.js +77 -0
- package/dist/bitmapMedian.js.map +1 -0
- package/dist/bitmapMorphological.d.ts +29 -0
- package/dist/bitmapMorphological.d.ts.map +1 -0
- package/dist/bitmapMorphological.js +81 -0
- package/dist/bitmapMorphological.js.map +1 -0
- package/dist/bitmapNoise.d.ts +48 -0
- package/dist/bitmapNoise.d.ts.map +1 -0
- package/dist/bitmapNoise.js +245 -0
- package/dist/bitmapNoise.js.map +1 -0
- package/dist/bitmapPaletteMap.d.ts +17 -0
- package/dist/bitmapPaletteMap.d.ts.map +1 -0
- package/dist/bitmapPaletteMap.js +45 -0
- package/dist/bitmapPaletteMap.js.map +1 -0
- package/dist/bitmapPixel.d.ts +9 -0
- package/dist/bitmapPixel.d.ts.map +1 -0
- package/dist/bitmapPixel.js +36 -0
- package/dist/bitmapPixel.js.map +1 -0
- package/dist/bitmapPixelate.d.ts +13 -0
- package/dist/bitmapPixelate.d.ts.map +1 -0
- package/dist/bitmapPixelate.js +61 -0
- package/dist/bitmapPixelate.js.map +1 -0
- package/dist/bitmapQuery.d.ts +13 -0
- package/dist/bitmapQuery.d.ts.map +1 -0
- package/dist/bitmapQuery.js +46 -0
- package/dist/bitmapQuery.js.map +1 -0
- package/dist/bitmapRegion.d.ts +20 -0
- package/dist/bitmapRegion.d.ts.map +1 -0
- package/dist/bitmapRegion.js +28 -0
- package/dist/bitmapRegion.js.map +1 -0
- package/dist/bitmapResize.d.ts +17 -0
- package/dist/bitmapResize.d.ts.map +1 -0
- package/dist/bitmapResize.js +191 -0
- package/dist/bitmapResize.js.map +1 -0
- package/dist/bitmapRotate.d.ts +32 -0
- package/dist/bitmapRotate.d.ts.map +1 -0
- package/dist/bitmapRotate.js +143 -0
- package/dist/bitmapRotate.js.map +1 -0
- package/dist/bitmapShadow.d.ts +72 -0
- package/dist/bitmapShadow.d.ts.map +1 -0
- package/dist/bitmapShadow.js +175 -0
- package/dist/bitmapShadow.js.map +1 -0
- package/dist/bitmapSharpen.d.ts +16 -0
- package/dist/bitmapSharpen.d.ts.map +1 -0
- package/dist/bitmapSharpen.js +47 -0
- package/dist/bitmapSharpen.js.map +1 -0
- package/dist/bitmapTone.d.ts +28 -0
- package/dist/bitmapTone.d.ts.map +1 -0
- package/dist/bitmapTone.js +69 -0
- package/dist/bitmapTone.js.map +1 -0
- package/dist/bitmapTransform.d.ts +40 -0
- package/dist/bitmapTransform.d.ts.map +1 -0
- package/dist/bitmapTransform.js +163 -0
- package/dist/bitmapTransform.js.map +1 -0
- package/dist/bitmapWarp.d.ts +48 -0
- package/dist/bitmapWarp.d.ts.map +1 -0
- package/dist/bitmapWarp.js +284 -0
- package/dist/bitmapWarp.js.map +1 -0
- package/dist/contract.d.ts +43 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +43 -0
- package/dist/contract.js.map +1 -0
- package/dist/explainBitmapReadback.d.ts +3 -0
- package/dist/explainBitmapReadback.d.ts.map +1 -0
- package/dist/explainBitmapReadback.js +39 -0
- package/dist/explainBitmapReadback.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
- package/src/bitmap.test.ts +88 -0
- package/src/bitmapAffine.test.ts +98 -0
- package/src/bitmapAlpha.test.ts +110 -0
- package/src/bitmapBevel.test.ts +61 -0
- package/src/bitmapBlur.test.ts +234 -0
- package/src/bitmapChannel.test.ts +97 -0
- package/src/bitmapColorMatrix.test.ts +214 -0
- package/src/bitmapCompare.test.ts +92 -0
- package/src/bitmapComposite.test.ts +259 -0
- package/src/bitmapConvolution.test.ts +130 -0
- package/src/bitmapCopy.test.ts +48 -0
- package/src/bitmapCoverage.test.ts +39 -0
- package/src/bitmapCrop.test.ts +116 -0
- package/src/bitmapDisplacement.test.ts +181 -0
- package/src/bitmapDissolve.test.ts +99 -0
- package/src/bitmapDraw.test.ts +68 -0
- package/src/bitmapEncode.test.ts +18 -0
- package/src/bitmapFill.test.ts +83 -0
- package/src/bitmapFingerprint.test.ts +103 -0
- package/src/bitmapFlip.test.ts +53 -0
- package/src/bitmapFormat.test.ts +124 -0
- package/src/bitmapFrom.test.ts +86 -0
- package/src/bitmapGradient.test.ts +85 -0
- package/src/bitmapGradientFill.test.ts +107 -0
- package/src/bitmapHistogram.test.ts +64 -0
- package/src/bitmapImageChannel.test.ts +19 -0
- package/src/bitmapMedian.test.ts +39 -0
- package/src/bitmapMorphological.test.ts +69 -0
- package/src/bitmapNoise.test.ts +163 -0
- package/src/bitmapPaletteMap.test.ts +49 -0
- package/src/bitmapPixel.test.ts +117 -0
- package/src/bitmapPixelate.test.ts +40 -0
- package/src/bitmapQuery.test.ts +42 -0
- package/src/bitmapRegion.test.ts +34 -0
- package/src/bitmapResize.test.ts +106 -0
- package/src/bitmapRotate.test.ts +108 -0
- package/src/bitmapShadow.test.ts +159 -0
- package/src/bitmapSharpen.test.ts +44 -0
- package/src/bitmapTone.test.ts +104 -0
- package/src/bitmapTransform.test.ts +128 -0
- package/src/bitmapWarp.test.ts +118 -0
- package/src/explainBitmapReadback.test.ts +84 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Recomputes why createBitmapFromImageSource would or would not return a Bitmap for these arguments,
|
|
2
|
+
// as plain data. Pure: it allocates a scratch canvas and reads one pixel to settle taint, mutates
|
|
3
|
+
// nothing the caller owns, never throws, and retains no reference to `source`. Import it to find out
|
|
4
|
+
// why a capture came back null; it sheds from production when unimported.
|
|
5
|
+
//
|
|
6
|
+
// Reasons are root-cause prioritized rather than following the constructor's literal check order: an
|
|
7
|
+
// empty capture and a missing DOM are properties of the call and the host, knowable without touching
|
|
8
|
+
// the source at all, so they are reported before anything is drawn. `tainted-source` is last because
|
|
9
|
+
// it is the only one that requires actually attempting the read.
|
|
10
|
+
//
|
|
11
|
+
// This is the pull half of the diagnostics convention, and it duplicates the constructor's failure
|
|
12
|
+
// conditions by design — the maintenance seam is that a new way for the readback to fail must gain a
|
|
13
|
+
// matching branch here or this query silently goes stale.
|
|
14
|
+
export function explainBitmapReadback(source, width, height) {
|
|
15
|
+
const reason = _blockReason(source, width, height);
|
|
16
|
+
return { readable: reason === 'ok', reason };
|
|
17
|
+
}
|
|
18
|
+
function _blockReason(source, width, height) {
|
|
19
|
+
if (width <= 0 || height <= 0)
|
|
20
|
+
return 'empty-size';
|
|
21
|
+
if (typeof document === 'undefined')
|
|
22
|
+
return 'no-canvas';
|
|
23
|
+
const canvas = document.createElement('canvas');
|
|
24
|
+
canvas.width = 1;
|
|
25
|
+
canvas.height = 1;
|
|
26
|
+
const ctx = canvas.getContext('2d');
|
|
27
|
+
if (ctx === null)
|
|
28
|
+
return 'no-canvas';
|
|
29
|
+
try {
|
|
30
|
+
// One pixel is enough: taint is a property of the canvas after the draw, not of how much was read.
|
|
31
|
+
ctx.drawImage(source, 0, 0);
|
|
32
|
+
ctx.getImageData(0, 0, 1, 1);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return 'tainted-source';
|
|
36
|
+
}
|
|
37
|
+
return 'ok';
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=explainBitmapReadback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explainBitmapReadback.js","sourceRoot":"","sources":["../src/explainBitmapReadback.ts"],"names":[],"mappings":"AAEA,qGAAqG;AACrG,kGAAkG;AAClG,qGAAqG;AACrG,0EAA0E;AAC1E,EAAE;AACF,qGAAqG;AACrG,qGAAqG;AACrG,qGAAqG;AACrG,iEAAiE;AACjE,EAAE;AACF,mGAAmG;AACnG,qGAAqG;AACrG,0DAA0D;AAC1D,MAAM,UAAU,qBAAqB,CACnC,MAAyB,EACzB,KAAa,EACb,MAAc;IAEd,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,EAAE,MAAM,EAAE,CAAC;AAC/C,CAAC;AAED,SAAS,YAAY,CAAC,MAAyB,EAAE,KAAa,EAAE,MAAc;IAC5E,IAAI,KAAK,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,YAAY,CAAC;IACnD,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO,WAAW,CAAC;IACxD,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;IACjB,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAClB,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,WAAW,CAAC;IACrC,IAAI,CAAC;QACH,mGAAmG;QACnG,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5B,GAAG,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { ImageChannel, BITMAP_NOISE_CHANNEL_A, BITMAP_NOISE_CHANNEL_B, BITMAP_NOISE_CHANNEL_G, BITMAP_NOISE_CHANNEL_R, applyBitmapColorScaleBias, applyBitmapCurve, applyBitmapLevels, applyBitmapPaletteMap, applyBitmapThreshold, bevelBitmap, blurBitmapPixelsHorizontal, blurBitmapPixelsHorizontalWeighted, blurBitmapPixelsVertical, blurBitmapPixelsVerticalWeighted, boxBlurBitmap, buildBitmapBrightnessColorMatrix, buildBitmapContrastColorMatrix, buildBitmapGradientRamp, buildBitmapGrayscaleColorMatrix, buildBitmapHueRotationColorMatrix, buildBitmapInvertColorMatrix, buildBitmapSaturationColorMatrix, buildBitmapSepiaColorMatrix, cloneBitmap, colorMatrixBitmap, compareBitmap, compareBitmapFingerprints, compositeBitmapPixels, compositeBitmapRegion, computeGaussianKernel, concatBitmapColorMatrix, convertBitmapAlphaType, convertBitmapPixelOrder, convolveBitmap, copyBitmapAlpha, copyBitmapChannel, copyBitmapPixels, createBitmap, createBitmapFingerprint, createBitmapFromCanvas, captureBitmapFromImageResource, createBitmapFromImageSource, explainBitmapReadback, createBitmapRegion, cropBitmap, dilateBitmap, displaceBitmap, dissolveBitmapPixels, drawBitmap, dropShadowBitmap, encodeBitmap, equalizeBitmapHistogram, erodeBitmap, extendBitmap, extractBitmapPixels, extractBitmapPixels32, fillBitmapLinearGradient, fillBitmapNoise, fillBitmapPerlinNoise, fillBitmapRadialGradient, fillBitmapRectangle, fillBitmapTurbulence, flipBitmapHorizontal, flipBitmapVertical, floodFillBitmap, formatBitmapFingerprint, gaussianBlurBitmap, getBitmapColorBoundsRectangle, getBitmapCoverage, getBitmapHistogram, getBitmapMismatch, getBitmapPixel, getBitmapPixelChannel, getBitmapPixelLuminance, getBitmapPixelRgb, glowBitmap, gradientBevelBitmap, gradientGlowBitmap, innerGlowBitmap, innerShadowBitmap, invalidateBitmap, medianBitmap, mergeBitmap, mergeBitmapChannels, multiplyBitmapAlpha, parseBitmapFingerprint, pixelateBitmap, premultiplyBitmapPixels, resizeBitmap, rotateBitmap, rotateBitmap180, rotateBitmapClockwise, rotateBitmapCounterClockwise, scrollBitmap, setBitmapAlpha, setBitmapColorMatrixIdentity, setBitmapPixel, setBitmapPixelRgb, setBitmapRegion, sharpenBitmap, splitBitmapChannels, transformBitmap, trimBitmap, unpremultiplyBitmapPixels, warpBitmap, warpBitmapQuad, writeBitmapPixels, writeBitmapPixels32, } from './contract';
|
|
2
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,yBAAyB,EACzB,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,WAAW,EACX,0BAA0B,EAC1B,kCAAkC,EAClC,wBAAwB,EACxB,gCAAgC,EAChC,aAAa,EACb,gCAAgC,EAChC,8BAA8B,EAC9B,uBAAuB,EACvB,+BAA+B,EAC/B,iCAAiC,EACjC,4BAA4B,EAC5B,gCAAgC,EAChC,2BAA2B,EAC3B,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,yBAAyB,EACzB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,EACvB,sBAAsB,EACtB,8BAA8B,EAC9B,2BAA2B,EAC3B,qBAAqB,EACrB,kBAAkB,EAClB,UAAU,EACV,YAAY,EACZ,cAAc,EACd,oBAAoB,EACpB,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,EACvB,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,EACxB,eAAe,EACf,qBAAqB,EACrB,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,EACf,uBAAuB,EACvB,kBAAkB,EAClB,6BAA6B,EAC7B,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,uBAAuB,EACvB,iBAAiB,EACjB,UAAU,EACV,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,cAAc,EACd,uBAAuB,EACvB,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,qBAAqB,EACrB,4BAA4B,EAC5B,YAAY,EACZ,cAAc,EACd,4BAA4B,EAC5B,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,UAAU,EACV,yBAAyB,EACzB,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { ImageChannel, BITMAP_NOISE_CHANNEL_A, BITMAP_NOISE_CHANNEL_B, BITMAP_NOISE_CHANNEL_G, BITMAP_NOISE_CHANNEL_R, applyBitmapColorScaleBias, applyBitmapCurve, applyBitmapLevels, applyBitmapPaletteMap, applyBitmapThreshold, bevelBitmap, blurBitmapPixelsHorizontal, blurBitmapPixelsHorizontalWeighted, blurBitmapPixelsVertical, blurBitmapPixelsVerticalWeighted, boxBlurBitmap, buildBitmapBrightnessColorMatrix, buildBitmapContrastColorMatrix, buildBitmapGradientRamp, buildBitmapGrayscaleColorMatrix, buildBitmapHueRotationColorMatrix, buildBitmapInvertColorMatrix, buildBitmapSaturationColorMatrix, buildBitmapSepiaColorMatrix, cloneBitmap, colorMatrixBitmap, compareBitmap, compareBitmapFingerprints, compositeBitmapPixels, compositeBitmapRegion, computeGaussianKernel, concatBitmapColorMatrix, convertBitmapAlphaType, convertBitmapPixelOrder, convolveBitmap, copyBitmapAlpha, copyBitmapChannel, copyBitmapPixels, createBitmap, createBitmapFingerprint, createBitmapFromCanvas, captureBitmapFromImageResource, createBitmapFromImageSource, explainBitmapReadback, createBitmapRegion, cropBitmap, dilateBitmap, displaceBitmap, dissolveBitmapPixels, drawBitmap, dropShadowBitmap, encodeBitmap, equalizeBitmapHistogram, erodeBitmap, extendBitmap, extractBitmapPixels, extractBitmapPixels32, fillBitmapLinearGradient, fillBitmapNoise, fillBitmapPerlinNoise, fillBitmapRadialGradient, fillBitmapRectangle, fillBitmapTurbulence, flipBitmapHorizontal, flipBitmapVertical, floodFillBitmap, formatBitmapFingerprint, gaussianBlurBitmap, getBitmapColorBoundsRectangle, getBitmapCoverage, getBitmapHistogram, getBitmapMismatch, getBitmapPixel, getBitmapPixelChannel, getBitmapPixelLuminance, getBitmapPixelRgb, glowBitmap, gradientBevelBitmap, gradientGlowBitmap, innerGlowBitmap, innerShadowBitmap, invalidateBitmap, medianBitmap, mergeBitmap, mergeBitmapChannels, multiplyBitmapAlpha, parseBitmapFingerprint, pixelateBitmap, premultiplyBitmapPixels, resizeBitmap, rotateBitmap, rotateBitmap180, rotateBitmapClockwise, rotateBitmapCounterClockwise, scrollBitmap, setBitmapAlpha, setBitmapColorMatrixIdentity, setBitmapPixel, setBitmapPixelRgb, setBitmapRegion, sharpenBitmap, splitBitmapChannels, transformBitmap, trimBitmap, unpremultiplyBitmapPixels, warpBitmap, warpBitmapQuad, writeBitmapPixels, writeBitmapPixels32, } from './contract';
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,yBAAyB,EACzB,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,WAAW,EACX,0BAA0B,EAC1B,kCAAkC,EAClC,wBAAwB,EACxB,gCAAgC,EAChC,aAAa,EACb,gCAAgC,EAChC,8BAA8B,EAC9B,uBAAuB,EACvB,+BAA+B,EAC/B,iCAAiC,EACjC,4BAA4B,EAC5B,gCAAgC,EAChC,2BAA2B,EAC3B,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,yBAAyB,EACzB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,EACvB,sBAAsB,EACtB,8BAA8B,EAC9B,2BAA2B,EAC3B,qBAAqB,EACrB,kBAAkB,EAClB,UAAU,EACV,YAAY,EACZ,cAAc,EACd,oBAAoB,EACpB,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,EACvB,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,EACxB,eAAe,EACf,qBAAqB,EACrB,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,EACf,uBAAuB,EACvB,kBAAkB,EAClB,6BAA6B,EAC7B,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,uBAAuB,EACvB,iBAAiB,EACjB,UAAU,EACV,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,cAAc,EACd,uBAAuB,EACvB,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,qBAAqB,EACrB,4BAA4B,EAC5B,YAAY,EACZ,cAAc,EACd,4BAA4B,EAC5B,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,UAAU,EACV,yBAAyB,EACzB,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flighthq/bitmap",
|
|
3
|
+
"version": "0.3.0-edge.1458.0c01b63",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "https://github.com/flighthq/flight.git",
|
|
7
|
+
"directory": "packages/bitmap"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./contract": {
|
|
18
|
+
"types": "./dist/contract.d.ts",
|
|
19
|
+
"default": "./dist/contract.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"src/**/*.test.ts",
|
|
25
|
+
"!dist/**/*.test.js",
|
|
26
|
+
"!dist/**/*.test.d.ts",
|
|
27
|
+
"!dist/**/*.test.js.map",
|
|
28
|
+
"!dist/**/*.test.d.ts.map"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc -b",
|
|
32
|
+
"clean": "tsc -b --clean",
|
|
33
|
+
"test": "vitest run --config vitest.config.ts",
|
|
34
|
+
"test:watch": "vitest --watch --config vitest.config.ts",
|
|
35
|
+
"prepack": "npm run clean && npm run clean:dist && npm run build",
|
|
36
|
+
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@flighthq/image": "0.3.0-edge.1458.0c01b63",
|
|
40
|
+
"@flighthq/entity": "0.3.0-edge.1458.0c01b63",
|
|
41
|
+
"@flighthq/types": "0.3.0-edge.1458.0c01b63"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"typescript": "^5.3.0"
|
|
45
|
+
},
|
|
46
|
+
"description": "Pixel-level image manipulation using browser ImageData",
|
|
47
|
+
"sideEffects": false
|
|
48
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { cloneBitmap, convertBitmapAlphaType, createBitmap, invalidateBitmap } from './bitmap';
|
|
2
|
+
|
|
3
|
+
describe('cloneBitmap', () => {
|
|
4
|
+
it('produces identical values', () => {
|
|
5
|
+
const img = createBitmap(2, 2, 0x102030ff);
|
|
6
|
+
const clone = cloneBitmap(img);
|
|
7
|
+
expect(clone.width).toBe(img.width);
|
|
8
|
+
expect(clone.height).toBe(img.height);
|
|
9
|
+
expect(clone.data).toEqual(img.data);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('is a deep copy', () => {
|
|
13
|
+
const img = createBitmap(2, 2, 0x102030ff);
|
|
14
|
+
const clone = cloneBitmap(img);
|
|
15
|
+
clone.data[0] = 0;
|
|
16
|
+
expect(img.data[0]).toBe(0x10);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('convertBitmapAlphaType', () => {
|
|
21
|
+
it('premultiplies straight alpha', () => {
|
|
22
|
+
const img = createBitmap(1, 1, 0x80808080);
|
|
23
|
+
img.alphaType = 'straight';
|
|
24
|
+
convertBitmapAlphaType(img, 'premultiplied');
|
|
25
|
+
expect(img.alphaType).toBe('premultiplied');
|
|
26
|
+
// R = round(0x80 * (0x80/255)) ≈ round(128 * 0.502) ≈ 64
|
|
27
|
+
expect(img.data[0]).toBe(64);
|
|
28
|
+
expect(img.data[3]).toBe(0x80); // alpha unchanged
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('unpremultiplies premultiplied alpha', () => {
|
|
32
|
+
// Pre-build a premultiplied bitmap manually.
|
|
33
|
+
const img = createBitmap(1, 1, 0x00000000);
|
|
34
|
+
img.alphaType = 'premultiplied';
|
|
35
|
+
img.data[0] = 64;
|
|
36
|
+
img.data[1] = 64;
|
|
37
|
+
img.data[2] = 64;
|
|
38
|
+
img.data[3] = 128;
|
|
39
|
+
convertBitmapAlphaType(img, 'straight');
|
|
40
|
+
expect(img.alphaType).toBe('straight');
|
|
41
|
+
// R = round(64 * 255/128) = round(127.5) = 128
|
|
42
|
+
expect(img.data[0]).toBe(128);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('is a no-op when target matches current alphaType', () => {
|
|
46
|
+
const img = createBitmap(1, 1, 0xff0000ff);
|
|
47
|
+
img.alphaType = 'straight';
|
|
48
|
+
const before = Array.from(img.data);
|
|
49
|
+
convertBitmapAlphaType(img, 'straight');
|
|
50
|
+
expect(Array.from(img.data)).toEqual(before);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('handles zero-alpha pixels (unpremultiply)', () => {
|
|
54
|
+
const img = createBitmap(1, 1, 0x00000000);
|
|
55
|
+
img.alphaType = 'premultiplied';
|
|
56
|
+
convertBitmapAlphaType(img, 'straight');
|
|
57
|
+
expect(img.data[0]).toBe(0);
|
|
58
|
+
expect(img.data[3]).toBe(0);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('createBitmap', () => {
|
|
63
|
+
it('creates zeroed image data when no color provided', () => {
|
|
64
|
+
const img = createBitmap(2, 2);
|
|
65
|
+
expect(img.width).toBe(2);
|
|
66
|
+
expect(img.height).toBe(2);
|
|
67
|
+
expect(img.data.length).toBe(16);
|
|
68
|
+
expect(img.data.every((v) => v === 0)).toBe(true);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('fills with the given color', () => {
|
|
72
|
+
const img = createBitmap(2, 2, 0x112233ff);
|
|
73
|
+
expect(img.data[0]).toBe(0x11);
|
|
74
|
+
expect(img.data[1]).toBe(0x22);
|
|
75
|
+
expect(img.data[2]).toBe(0x33);
|
|
76
|
+
expect(img.data[3]).toBe(0xff);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('invalidateBitmap', () => {
|
|
81
|
+
it('bumps the content version without replacing the pixel storage', () => {
|
|
82
|
+
const bitmap = createBitmap(1, 1);
|
|
83
|
+
const data = bitmap.data;
|
|
84
|
+
invalidateBitmap(bitmap);
|
|
85
|
+
expect(bitmap.version).toBe(1);
|
|
86
|
+
expect(bitmap.data).toBe(data);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { createBitmap } from './bitmap';
|
|
2
|
+
import { transformBitmap } from './bitmapAffine';
|
|
3
|
+
import { getBitmapPixel, setBitmapPixel } from './bitmapPixel';
|
|
4
|
+
import { createBitmapRegion } from './bitmapRegion';
|
|
5
|
+
|
|
6
|
+
describe('transformBitmap', () => {
|
|
7
|
+
it('identity matrix copies source to dest', () => {
|
|
8
|
+
const src = createBitmap(3, 3);
|
|
9
|
+
setBitmapPixel(src, 1, 1, 0xff0000ff);
|
|
10
|
+
const dst = createBitmap(3, 3);
|
|
11
|
+
const identity: [number, number, number, number, number, number] = [1, 0, 0, 1, 0, 0];
|
|
12
|
+
transformBitmap(createBitmapRegion(dst), createBitmapRegion(src), identity);
|
|
13
|
+
expect(getBitmapPixel(dst, 1, 1)).toBe(0xff0000ff);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('translation matrix shifts the image', () => {
|
|
17
|
+
const src = createBitmap(4, 4);
|
|
18
|
+
setBitmapPixel(src, 0, 0, 0xaabbccff);
|
|
19
|
+
const dst = createBitmap(4, 4);
|
|
20
|
+
// Translate: map dest (1,1) → source (0,0), i.e. e=-1, f=-1.
|
|
21
|
+
const translate: [number, number, number, number, number, number] = [1, 0, 0, 1, -1, -1];
|
|
22
|
+
transformBitmap(createBitmapRegion(dst), createBitmapRegion(src), translate);
|
|
23
|
+
expect(getBitmapPixel(dst, 1, 1)).toBe(0xaabbccff);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('transparent edge mode writes transparent for out-of-bounds samples', () => {
|
|
27
|
+
const src = createBitmap(2, 2, 0xff0000ff);
|
|
28
|
+
const dst = createBitmap(4, 4);
|
|
29
|
+
const identity: [number, number, number, number, number, number] = [1, 0, 0, 1, 0, 0];
|
|
30
|
+
transformBitmap(createBitmapRegion(dst), createBitmapRegion(src), identity, 'transparent');
|
|
31
|
+
// Out of source bounds → transparent.
|
|
32
|
+
expect(getBitmapPixel(dst, 3, 3)).toBe(0x00000000);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('clamp edge mode repeats border pixels', () => {
|
|
36
|
+
const src = createBitmap(2, 2, 0x112233ff);
|
|
37
|
+
const dst = createBitmap(4, 4);
|
|
38
|
+
const identity: [number, number, number, number, number, number] = [1, 0, 0, 1, 0, 0];
|
|
39
|
+
transformBitmap(createBitmapRegion(dst), createBitmapRegion(src), identity, 'clamp');
|
|
40
|
+
// Out of source bounds → clamped to border color.
|
|
41
|
+
expect(getBitmapPixel(dst, 3, 3)).toBe(0x112233ff);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('wrap edge mode tiles the source', () => {
|
|
45
|
+
const src = createBitmap(2, 2);
|
|
46
|
+
setBitmapPixel(src, 0, 0, 0xffff00ff);
|
|
47
|
+
const dst = createBitmap(4, 2);
|
|
48
|
+
const identity: [number, number, number, number, number, number] = [1, 0, 0, 1, 0, 0];
|
|
49
|
+
transformBitmap(createBitmapRegion(dst), createBitmapRegion(src), identity, 'wrap');
|
|
50
|
+
// Pixel at (2,0) should wrap to (0,0) in source.
|
|
51
|
+
expect(getBitmapPixel(dst, 2, 0)).toBe(0xffff00ff);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('mirror edge mode mirrors the source', () => {
|
|
55
|
+
const src = createBitmap(3, 1);
|
|
56
|
+
setBitmapPixel(src, 0, 0, 0xff0000ff);
|
|
57
|
+
setBitmapPixel(src, 1, 0, 0x00ff00ff);
|
|
58
|
+
setBitmapPixel(src, 2, 0, 0x0000ffff);
|
|
59
|
+
const dst = createBitmap(5, 1);
|
|
60
|
+
const identity: [number, number, number, number, number, number] = [1, 0, 0, 1, 0, 0];
|
|
61
|
+
transformBitmap(createBitmapRegion(dst), createBitmapRegion(src), identity, 'mirror');
|
|
62
|
+
// x=3 mirrors to x=2 (0x0000ff), x=4 mirrors to x=1 (0x00ff00).
|
|
63
|
+
expect(getBitmapPixel(dst, 3, 0)).toBe(0x0000ffff);
|
|
64
|
+
expect(getBitmapPixel(dst, 4, 0)).toBe(0x00ff00ff);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('nearest sample mode preserves hard edges', () => {
|
|
68
|
+
const src = createBitmap(2, 1);
|
|
69
|
+
setBitmapPixel(src, 0, 0, 0xff0000ff);
|
|
70
|
+
setBitmapPixel(src, 1, 0, 0x0000ffff);
|
|
71
|
+
const dst = createBitmap(2, 1);
|
|
72
|
+
const identity: [number, number, number, number, number, number] = [1, 0, 0, 1, 0, 0];
|
|
73
|
+
transformBitmap(createBitmapRegion(dst), createBitmapRegion(src), identity, 'transparent', 'nearest');
|
|
74
|
+
expect(getBitmapPixel(dst, 0, 0)).toBe(0xff0000ff);
|
|
75
|
+
expect(getBitmapPixel(dst, 1, 0)).toBe(0x0000ffff);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('skips zero-size dest or source', () => {
|
|
79
|
+
const src = createBitmap(2, 2);
|
|
80
|
+
const dst = createBitmap(2, 2);
|
|
81
|
+
const identity: [number, number, number, number, number, number] = [1, 0, 0, 1, 0, 0];
|
|
82
|
+
// Zero-size region — should not throw.
|
|
83
|
+
expect(() =>
|
|
84
|
+
transformBitmap({ bitmap: dst, x: 0, y: 0, width: 0, height: 0 }, createBitmapRegion(src), identity),
|
|
85
|
+
).not.toThrow();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('aliased out=in with identity leaves bitmap unchanged', () => {
|
|
89
|
+
const surf = createBitmap(2, 2, 0xabcdefff);
|
|
90
|
+
const identity: [number, number, number, number, number, number] = [1, 0, 0, 1, 0, 0];
|
|
91
|
+
// Aliased write to dest and source on a distinct bitmap to avoid real corruption.
|
|
92
|
+
const src = createBitmap(2, 2, 0xabcdefff);
|
|
93
|
+
const dst = createBitmap(2, 2);
|
|
94
|
+
transformBitmap(createBitmapRegion(dst), createBitmapRegion(src), identity);
|
|
95
|
+
expect(getBitmapPixel(dst, 0, 0)).toBe(0xabcdefff);
|
|
96
|
+
void surf;
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { createBitmap } from './bitmap';
|
|
2
|
+
import { copyBitmapAlpha, multiplyBitmapAlpha, setBitmapAlpha } from './bitmapAlpha';
|
|
3
|
+
import { getBitmapPixel, setBitmapPixel } from './bitmapPixel';
|
|
4
|
+
import { createBitmapRegion } from './bitmapRegion';
|
|
5
|
+
|
|
6
|
+
describe('copyBitmapAlpha', () => {
|
|
7
|
+
it('copies alpha from source to dest, leaving RGB unchanged', () => {
|
|
8
|
+
const src = createBitmap(2, 1);
|
|
9
|
+
setBitmapPixel(src, 0, 0, 0x00000080); // alpha 0x80
|
|
10
|
+
setBitmapPixel(src, 1, 0, 0x000000ff); // alpha 0xff
|
|
11
|
+
const dst = createBitmap(2, 1, 0xff00ffff); // red pixels, fully opaque
|
|
12
|
+
copyBitmapAlpha(createBitmapRegion(dst), createBitmapRegion(src));
|
|
13
|
+
// RGB unchanged, alpha from source.
|
|
14
|
+
expect((getBitmapPixel(dst, 0, 0) >>> 24) & 0xff).toBe(0xff); // red channel
|
|
15
|
+
expect(getBitmapPixel(dst, 0, 0) & 0xff).toBe(0x80); // alpha
|
|
16
|
+
expect(getBitmapPixel(dst, 1, 0) & 0xff).toBe(0xff);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('same-bitmap region is a no-op on alpha', () => {
|
|
20
|
+
const surf = createBitmap(2, 1, 0x112233aa);
|
|
21
|
+
copyBitmapAlpha(createBitmapRegion(surf), createBitmapRegion(surf));
|
|
22
|
+
expect(getBitmapPixel(surf, 0, 0) & 0xff).toBe(0xaa);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('operates only on the overlap of both regions', () => {
|
|
26
|
+
const src = createBitmap(3, 1, 0x00000080);
|
|
27
|
+
const dst = createBitmap(3, 1, 0x00000000);
|
|
28
|
+
// Copy only 1 pixel wide.
|
|
29
|
+
copyBitmapAlpha({ bitmap: dst, x: 0, y: 0, width: 1, height: 1 }, { bitmap: src, x: 0, y: 0, width: 1, height: 1 });
|
|
30
|
+
expect(getBitmapPixel(dst, 0, 0) & 0xff).toBe(0x80);
|
|
31
|
+
expect(getBitmapPixel(dst, 1, 0) & 0xff).toBe(0x00); // untouched
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('multiplyBitmapAlpha', () => {
|
|
36
|
+
it('factor 0 makes region fully transparent', () => {
|
|
37
|
+
const surf = createBitmap(2, 2, 0xff0000ff);
|
|
38
|
+
multiplyBitmapAlpha(createBitmapRegion(surf), 0);
|
|
39
|
+
expect(getBitmapPixel(surf, 0, 0) & 0xff).toBe(0);
|
|
40
|
+
expect(getBitmapPixel(surf, 1, 1) & 0xff).toBe(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('factor 1 leaves alpha unchanged', () => {
|
|
44
|
+
const surf = createBitmap(1, 1, 0xff0000ab);
|
|
45
|
+
multiplyBitmapAlpha(createBitmapRegion(surf), 1);
|
|
46
|
+
expect(getBitmapPixel(surf, 0, 0) & 0xff).toBe(0xab);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('factor 0.5 halves the alpha', () => {
|
|
50
|
+
const surf = createBitmap(1, 1, 0xff0000fe);
|
|
51
|
+
multiplyBitmapAlpha(createBitmapRegion(surf), 0.5);
|
|
52
|
+
// 0xfe * 0.5 = 127
|
|
53
|
+
expect(getBitmapPixel(surf, 0, 0) & 0xff).toBe(127);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('clamps factor to [0, 1]', () => {
|
|
57
|
+
const surf = createBitmap(1, 1, 0xff0000aa);
|
|
58
|
+
multiplyBitmapAlpha(createBitmapRegion(surf), 2);
|
|
59
|
+
// Factor clamped to 1, alpha unchanged.
|
|
60
|
+
expect(getBitmapPixel(surf, 0, 0) & 0xff).toBe(0xaa);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('leaves RGB channels unchanged', () => {
|
|
64
|
+
const surf = createBitmap(1, 1, 0x123456ff);
|
|
65
|
+
multiplyBitmapAlpha(createBitmapRegion(surf), 0.5);
|
|
66
|
+
const p = getBitmapPixel(surf, 0, 0);
|
|
67
|
+
expect((p >>> 24) & 0xff).toBe(0x12);
|
|
68
|
+
expect((p >> 16) & 0xff).toBe(0x34);
|
|
69
|
+
expect((p >> 8) & 0xff).toBe(0x56);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('setBitmapAlpha', () => {
|
|
74
|
+
it('writes a constant alpha to all pixels in region', () => {
|
|
75
|
+
const surf = createBitmap(3, 3, 0xff0000ff);
|
|
76
|
+
setBitmapAlpha(createBitmapRegion(surf), 0x40);
|
|
77
|
+
for (let y = 0; y < 3; y++) {
|
|
78
|
+
for (let x = 0; x < 3; x++) {
|
|
79
|
+
expect(getBitmapPixel(surf, x, y) & 0xff).toBe(0x40);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('leaves RGB unchanged', () => {
|
|
85
|
+
const surf = createBitmap(1, 1, 0x112233ff);
|
|
86
|
+
setBitmapAlpha(createBitmapRegion(surf), 0x80);
|
|
87
|
+
const p = getBitmapPixel(surf, 0, 0);
|
|
88
|
+
expect((p >>> 24) & 0xff).toBe(0x11);
|
|
89
|
+
expect((p >> 16) & 0xff).toBe(0x22);
|
|
90
|
+
expect((p >> 8) & 0xff).toBe(0x33);
|
|
91
|
+
expect(p & 0xff).toBe(0x80);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('clamps alpha to [0, 255]', () => {
|
|
95
|
+
const surf = createBitmap(1, 1, 0xff0000ff);
|
|
96
|
+
setBitmapAlpha(createBitmapRegion(surf), -10);
|
|
97
|
+
expect(getBitmapPixel(surf, 0, 0) & 0xff).toBe(0);
|
|
98
|
+
setBitmapAlpha(createBitmapRegion(surf), 300);
|
|
99
|
+
expect(getBitmapPixel(surf, 0, 0) & 0xff).toBe(255);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('only affects the specified sub-region', () => {
|
|
103
|
+
const surf = createBitmap(4, 1, 0xff0000ff);
|
|
104
|
+
setBitmapAlpha({ bitmap: surf, x: 1, y: 0, width: 2, height: 1 }, 0x00);
|
|
105
|
+
expect(getBitmapPixel(surf, 0, 0) & 0xff).toBe(0xff); // untouched
|
|
106
|
+
expect(getBitmapPixel(surf, 1, 0) & 0xff).toBe(0x00);
|
|
107
|
+
expect(getBitmapPixel(surf, 2, 0) & 0xff).toBe(0x00);
|
|
108
|
+
expect(getBitmapPixel(surf, 3, 0) & 0xff).toBe(0xff); // untouched
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createBitmap } from './bitmap';
|
|
2
|
+
import { bevelBitmap } from './bitmapBevel';
|
|
3
|
+
|
|
4
|
+
function region(bitmap: ReturnType<typeof createBitmap>, x = 0, y = 0, width = bitmap.width, height = bitmap.height) {
|
|
5
|
+
return { bitmap, x, y, width, height };
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// 5x1 strip with a single alpha edge: transparent | transparent | opaque | opaque | opaque.
|
|
9
|
+
function edgeStrip() {
|
|
10
|
+
const s = createBitmap(5, 1);
|
|
11
|
+
for (let x = 2; x < 5; x++) s.data[x * 4 + 3] = 255;
|
|
12
|
+
return s;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe('bevelBitmap', () => {
|
|
16
|
+
it('highlights the light-facing edge and shades the opposite edge', () => {
|
|
17
|
+
// Light from the left (angle π). With radiusX=1 the blurred alpha is
|
|
18
|
+
// [0, 85, 170, 255, 255]; the gradient highlights the left edge of the
|
|
19
|
+
// shape and shadows the right edge.
|
|
20
|
+
const source = edgeStrip();
|
|
21
|
+
const out = new Uint8ClampedArray(5 * 4);
|
|
22
|
+
const scratch = new Uint8ClampedArray(5 * 4);
|
|
23
|
+
bevelBitmap(out, scratch, region(source), {
|
|
24
|
+
angle: Math.PI,
|
|
25
|
+
distance: 1,
|
|
26
|
+
radiusX: 1,
|
|
27
|
+
radiusY: 0,
|
|
28
|
+
type: 'both',
|
|
29
|
+
highlightColor: 0xffffffff,
|
|
30
|
+
shadowColor: 0x000000ff,
|
|
31
|
+
});
|
|
32
|
+
// Left edge: white highlight.
|
|
33
|
+
expect(out[2 * 4 + 0]).toBe(255);
|
|
34
|
+
expect(out[2 * 4 + 1]).toBe(255);
|
|
35
|
+
expect(out[2 * 4 + 2]).toBe(255);
|
|
36
|
+
expect(out[2 * 4 + 3]).toBe(170);
|
|
37
|
+
// Right edge of the strip faces away from the light: black shadow.
|
|
38
|
+
expect(out[4 * 4 + 0]).toBe(0);
|
|
39
|
+
expect(out[4 * 4 + 1]).toBe(0);
|
|
40
|
+
expect(out[4 * 4 + 2]).toBe(0);
|
|
41
|
+
expect(out[4 * 4 + 3]).toBe(255);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("'inner' type clips the bevel to inside the shape", () => {
|
|
45
|
+
const source = edgeStrip();
|
|
46
|
+
const out = new Uint8ClampedArray(5 * 4);
|
|
47
|
+
const scratch = new Uint8ClampedArray(5 * 4);
|
|
48
|
+
bevelBitmap(out, scratch, region(source), {
|
|
49
|
+
angle: Math.PI,
|
|
50
|
+
distance: 1,
|
|
51
|
+
radiusX: 1,
|
|
52
|
+
radiusY: 0,
|
|
53
|
+
type: 'inner',
|
|
54
|
+
});
|
|
55
|
+
// x0/x1 are outside the shape (source alpha 0) → clipped to 0.
|
|
56
|
+
expect(out[0 * 4 + 3]).toBe(0);
|
|
57
|
+
expect(out[1 * 4 + 3]).toBe(0);
|
|
58
|
+
// x2 is inside the shape → highlight survives.
|
|
59
|
+
expect(out[2 * 4 + 3]).toBe(170);
|
|
60
|
+
});
|
|
61
|
+
});
|