diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9601ceb --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +*.DS_Store diff --git a/encode.py b/encode.py index 269e15f..0a6e65a 100644 --- a/encode.py +++ b/encode.py @@ -1,7 +1,7 @@ import cv2 -file_path = "test2.bin" -img = cv2.imread('grayscale_gradient_half.png', cv2.IMREAD_GRAYSCALE) +file_path = "test3.bin" +img = cv2.imread('grayscale_gradient.png', cv2.IMREAD_GRAYSCALE) height, width = img.shape vals = [] @@ -11,5 +11,7 @@ for i in range(height): k = img[i, j] vals.append(k) +print(f'{len(vals)} bytes') + with open(file_path, "wb") as file: file.write(bytes(vals)) \ No newline at end of file diff --git a/generate.sh b/generate.sh index 2dbab18..fc6d850 100644 --- a/generate.sh +++ b/generate.sh @@ -4,3 +4,5 @@ FILE="${1}" OUTPUT="${2}" cat ${FILE} | qrencode -s 10 -8 -o "${OUTPUT}" + +#-O3 -flto diff --git a/index.html b/index.html new file mode 100644 index 0000000..cd0cb7a --- /dev/null +++ b/index.html @@ -0,0 +1,24 @@ + + + + + + + Content + + + + + + + +
+ + + + \ No newline at end of file diff --git a/src/content.js b/src/content.js new file mode 100644 index 0000000..37e56ba --- /dev/null +++ b/src/content.js @@ -0,0 +1,126 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var Content = /** @class */ (function () { + function Content() { + this.width = 19; + this.height = 14; + this.displayCanvas = document.getElementById('display'); + this.displayCtx = this.displayCanvas.getContext('2d'); + this.displayCanvas.height = this.height; + this.displayCanvas.width = this.width; + this.videoCanvas = document.getElementById('video'); //document.createElement('canvas') as HTMLCanvasElement; + this.videoCtx = this.videoCanvas.getContext('2d'); + this.startCamera(); + } + Content.prototype.startCamera = function () { + return __awaiter(this, void 0, void 0, function () { + var constraints, stream, error_1; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + constraints = { + video: { + width: { ideal: 4096 }, + height: { ideal: 2160 }, + facingMode: 'environment' + }, + audio: false + }; + _a.label = 1; + case 1: + _a.trys.push([1, 3, , 4]); + return [4 /*yield*/, navigator.mediaDevices.getUserMedia(constraints)]; + case 2: + stream = _a.sent(); + this.video = document.createElement('video'); + this.video.srcObject = stream; + this.video.height = stream.getVideoTracks()[0].getSettings().height; + this.video.width = stream.getVideoTracks()[0].getSettings().width; + this.video.play(); + this.videoCanvas.height = this.video.height; + this.videoCanvas.width = this.video.width; + document.querySelector('#data').innerText = "".concat(this.video.width, "x").concat(this.video.height); + this.video.addEventListener('play', this.drawCanvas.bind(this)); + return [3 /*break*/, 4]; + case 3: + error_1 = _a.sent(); + console.error('Error accessing camera:', error_1); + return [3 /*break*/, 4]; + case 4: return [2 /*return*/]; + } + }); + }); + }; + Content.prototype.drawCanvas = function () { + this.videoCtx.drawImage(this.video, 0, 0, this.videoCanvas.width, this.videoCanvas.height); + this.parse(); + requestAnimationFrame(this.drawCanvas.bind(this)); + }; + Content.prototype.parse = function () { + var rgba = this.videoCtx.getImageData(0, 0, this.videoCanvas.width, this.videoCanvas.height).data; + var code = null; + try { + //@ts-ignore + code = jsQR(rgba, this.videoCanvas.width, this.videoCanvas.height); + } + catch (err) { + // + } + if (code !== null && code.binaryData.length === 266) { + document.querySelector('#data').innerText = code.binaryData.toString(); + console.dir(code); + this.display(code.binaryData); + } + else { + console.log('No QR'); + } + }; + Content.prototype.display = function (data) { + for (this.i = 0; this.i < data.length; this.i++) { + this.val = data[this.i]; + this.x = this.i % this.width; + this.y = Math.floor(this.i / this.width); + this.displayCtx.fillStyle = "rgba(".concat(this.val, ",").concat(this.val, ",").concat(this.val, ",1.0)"); + this.displayCtx.fillRect(this.x, this.y, 1, 1); + } + }; + return Content; +}()); +(function main() { + new Content(); +})(); +//# sourceMappingURL=content.js.map \ No newline at end of file diff --git a/src/content.js.map b/src/content.js.map new file mode 100644 index 0000000..2b10efb --- /dev/null +++ b/src/content.js.map @@ -0,0 +1 @@ +{"version":3,"file":"content.js","sourceRoot":"","sources":["content.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/src/content.ts b/src/content.ts index 10e8ffd..c79d90c 100644 --- a/src/content.ts +++ b/src/content.ts @@ -1,12 +1,99 @@ class Content { - private width : number = 20; - private height : number = 15; + private width : number = 19; + private height : number = 14; + + private x : number; + private y : number; + private i : number; + private val : number; private displayCanvas : HTMLCanvasElement; private videoCanvas : HTMLCanvasElement; + private displayCtx : CanvasRenderingContext2D; + private videoCtx : CanvasRenderingContext2D; + + private video : HTMLVideoElement; + constructor () { this.displayCanvas = document.getElementById('display') as HTMLCanvasElement; + this.displayCtx = this.displayCanvas.getContext('2d'); + + this.displayCanvas.height = this.height; + this.displayCanvas.width = this.width; + + this.videoCanvas = document.getElementById('video') as HTMLCanvasElement; //document.createElement('canvas') as HTMLCanvasElement; + this.videoCtx = this.videoCanvas.getContext('2d'); + + this.startCamera(); + } + + async startCamera () { + const constraints : MediaStreamConstraints = { + video : { + width: { ideal: 4096 }, + height: { ideal: 2160 }, + facingMode: 'environment' + }, + audio: false + } + try { + const stream = await navigator.mediaDevices.getUserMedia(constraints); + this.video = document.createElement('video') as HTMLVideoElement; + + this.video.srcObject = stream; + this.video.height = stream.getVideoTracks()[0].getSettings().height; + this.video.width = stream.getVideoTracks()[0].getSettings().width; + this.video.play(); + + this.videoCanvas.height = this.video.height; + this.videoCanvas.width = this.video.width; + + (document.querySelector('#data') as HTMLDivElement).innerText = `${this.video.width}x${this.video.height}`; + + this.video.addEventListener('play', this.drawCanvas.bind(this)); + } catch (error) { + console.error('Error accessing camera:', error); + } + } + + private drawCanvas () { + this.videoCtx.drawImage(this.video, 0, 0, this.videoCanvas.width, this.videoCanvas.height); + this.parse(); + requestAnimationFrame(this.drawCanvas.bind(this)); + } + + private parse () { + const rgba : ImageData = this.videoCtx.getImageData( + 0, 0, this.videoCanvas.width, this.videoCanvas.height + ).data as any; + + let code : any = null + + try { + //@ts-ignore + code = jsQR(rgba, this.videoCanvas.width, this.videoCanvas.height); + } catch (err) { + // + } + + if (code !== null && code.binaryData.length === 266) { + (document.querySelector('#data') as HTMLDivElement).innerText = code.binaryData.toString(); + console.dir(code); + this.display(code.binaryData); + } else { + console.log('No QR') + } + } + + display (data : any[]) { + for (this.i = 0; this.i < data.length; this.i++) { + this.val = data[this.i]; + this.x = this.i % this.width; + this.y = Math.floor(this.i / this.width); + this.displayCtx.fillStyle = `rgba(${this.val},${this.val},${this.val},1.0)`; + this.displayCtx.fillRect(this.x, this.y, 1, 1); + } } }