Skip to content

Commit 1c19869

Browse files
committed
replaced invert context filter with invert function compliant with Safari
1 parent 7d9fb72 commit 1c19869

File tree

1 file changed

+74
-9
lines changed

1 file changed

+74
-9
lines changed

src/html5-qrcode.ts

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ export class Html5Qrcode {
269269

270270
private shouldScan: boolean;
271271
private flippedScan: boolean;
272+
private invertedScan: boolean;
272273

273274
// Nullable elements
274275
// TODO(mebjas): Reduce the state-fulness of this mammoth class, by splitting
@@ -338,6 +339,7 @@ export class Html5Qrcode {
338339
this.foreverScanTimeout;
339340
this.shouldScan = true;
340341
this.flippedScan = false;
342+
this.invertedScan = false;
341343
this.stateManagerProxy = StateManagerFactory.create();
342344
}
343345

@@ -1213,7 +1215,10 @@ export class Html5Qrcode {
12131215
internalConfig, qrCodeSuccessCallback, qrCodeErrorCallback);
12141216
}, this.getTimeoutFps(internalConfig.fps));
12151217
};
1216-
1218+
if(this.context) {
1219+
// apply invert function that replace this.context.filter = 'invert(X)'
1220+
this.context = this.invert(this.context, (this.invertedScan) ? '1' : '0');
1221+
}
12171222
// Try scanning normal frame and in case of failure, scan
12181223
// the inverted context if not explictly disabled.
12191224
// TODO(mebjas): Move this logic to decoding library.
@@ -1234,14 +1239,11 @@ export class Html5Qrcode {
12341239
}
12351240
this.flippedScan = false;
12361241
}
1237-
// previous scan failed, flipped scan failed, try to invert colors
1238-
if (this.context!.filter === "none" && this.flippedScan === false) {
1239-
this.context!.filter = "invert(1)";
1240-
} else {
1241-
// restore initial filter value
1242-
if (this.context!.filter === "invert(1)" && this.flippedScan === false) {
1243-
this.context!.filter = "none";
1244-
}
1242+
// previous scan failed, check if next time I shouldapply invert function with amount parameter set to 1 or 0
1243+
if (this.invertedScan === false && this.flippedScan === false) {
1244+
this.invertedScan = true;
1245+
} else if (this.invertedScan === true && this.flippedScan === false) {
1246+
this.invertedScan = false;
12451247
}
12461248
triggerNextScan();
12471249
} else {
@@ -1349,6 +1351,69 @@ export class Html5Qrcode {
13491351
const type = (typeof cameraIdOrConfig);
13501352
throw `Invalid type of 'cameraIdOrConfig' = ${type}`;
13511353
}
1354+
1355+
/**
1356+
* Method that replace CanvasRenderingContext2D.filter that is not supported from Safari
1357+
* https://github.com/davidenke/context-filter-polyfill/blob/main/src/filters/invert.filter.ts
1358+
* @param context
1359+
* @param amount from 0 to 1
1360+
*/
1361+
private invert(
1362+
context: CanvasRenderingContext2D,
1363+
amount: any = '0'
1364+
) {
1365+
amount = this.normalizeNumberPercentage(amount);
1366+
// do not manipulate without proper amount
1367+
if (amount <= 0) {
1368+
return context;
1369+
}
1370+
// a maximum of 100%
1371+
if (amount > 1) {
1372+
amount = 1;
1373+
}
1374+
const { height, width } = context.canvas;
1375+
const imageData = context.getImageData(0, 0, width, height);
1376+
const { data } = imageData;
1377+
const { length } = data;
1378+
1379+
// in rgba world, every
1380+
// n * 4 + 0 is red,
1381+
// n * 4 + 1 green and
1382+
// n * 4 + 2 is blue
1383+
// the fourth can be skipped as it's the alpha channel
1384+
for (let i = 0; i < length; i += 4) {
1385+
data[i + 0] = Math.abs(data[i + 0] - 255 * amount);
1386+
data[i + 1] = Math.abs(data[i + 1] - 255 * amount);
1387+
data[i + 2] = Math.abs(data[i + 2] - 255 * amount);
1388+
}
1389+
1390+
// set back image data to context
1391+
context.putImageData(imageData, 0, 0);
1392+
1393+
// return the context itself
1394+
return context;
1395+
}
1396+
1397+
/**
1398+
* filter options are often represented as number-percentage,
1399+
* means that they'll be percentages like `50%` or floating
1400+
* in-between 0 and 1 like `.5`, so we normalize them.
1401+
* https://developer.mozilla.org/en-US/docs/Web/CSS/filter#number-percentage
1402+
* https://github.com/davidenke/context-filter-polyfill/blob/main/src/utils/filter.utils.ts
1403+
* @param percentage
1404+
* @returns
1405+
*/
1406+
private normalizeNumberPercentage(
1407+
percentage: string
1408+
) {
1409+
let normalized = parseFloat(percentage);
1410+
// check for percentages and divide by a hundred
1411+
if (/%\s*?$/i.test(percentage)) {
1412+
normalized /= 100;
1413+
}
1414+
return normalized;
1415+
}
1416+
13521417
//#endregion
13531418

13541419
//#region Documented private methods for file based scanner.

0 commit comments

Comments
 (0)