Skip to content

Commit

Permalink
Merge pull request #48 from grandchef/refactor/decoupling-image-and-q…
Browse files Browse the repository at this point in the history
…rcode-libs

refactor: decoupling image and qrcode libs
  • Loading branch information
mazinsw committed May 4, 2023
2 parents 5837424 + c50e002 commit d602792
Show file tree
Hide file tree
Showing 23 changed files with 467 additions and 118 deletions.
4 changes: 0 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ node_modules/
# Coverage
coverage

# VS Code
.vscode
!.vscode/tasks.js

# JetBrains IDEs
.idea/

Expand Down
19 changes: 19 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Test and Watch",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "yarn",
"runtimeArgs": [
"test:debug"
],
"port": 9229
}
]
}
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
}
28 changes: 24 additions & 4 deletions __tests__/Printer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as path from 'path';
import * as fs from 'fs';
import { ImageManager } from 'escpos-buffer-image';
import { Image } from '../src';
import { Capability } from '../src/capabilities';
import InMemory from '../src/connection/InMemory';
Expand Down Expand Up @@ -127,8 +129,16 @@ describe('print formatted text', () => {

it('draw picture from file', async () => {
const connection = new InMemory();
const printer = await Printer.CONNECT('MP-4200 TH', connection);
const image = new Image(path.join(__dirname, 'resources/sample.png'));
const imageManager = new ImageManager();
const printer = await Printer.CONNECT(
'MP-4200 TH',
connection,
imageManager,
);
const imageData = await imageManager.loadImage(
path.join(__dirname, 'resources/sample.png'),
);
const image = new Image(imageData);
await printer.setAlignment(Align.Center);
await printer.draw(image);
await printer.setAlignment(Align.Left);
Expand All @@ -139,8 +149,18 @@ describe('print formatted text', () => {

it('draw picture from buffer', async () => {
const connection = new InMemory();
const printer = await Printer.CONNECT('MP-4200 TH', connection);
const image = new Image(load('sample.png'));
const imageManager = new ImageManager();
const printer = await Printer.CONNECT(
'MP-4200 TH',
connection,
imageManager,
);
// tslint:disable: non-literal-fs-path
const imageBuffer = fs.readFileSync(
path.join(__dirname, 'resources/sample.png'),
);
const imageData = await imageManager.loadImageFromBuffer(imageBuffer);
const image = new Image(imageData);
await printer.setAlignment(Align.Center);
await printer.draw(image);
await printer.setAlignment(Align.Left);
Expand Down
46 changes: 19 additions & 27 deletions __tests__/graphics/Image.spec.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,29 @@
import { load } from '../helper';
import * as path from 'path';
import { ImageManager } from 'escpos-buffer-image';

import { Image } from '../../src';
import { PNG } from '../../src';

describe('proccess images to printing format', () => {
it('load image from buffer', () => {
const image = new Image(load('sample.png'));
it('load image from buffer', async () => {
const imageManager = new ImageManager();
const imageData = await imageManager.loadImage(
path.join(__dirname, '../resources/sample.png'),
);
const image = new Image(imageData);
expect(image.width).toBe(180);
});

it('allow image cache', () => {
const cache = new Image(load('sample.png'));
const image = new Image();
it('allow image cache', async () => {
const imageManager = new ImageManager();
const imageDataCache = await imageManager.loadImage(
path.join(__dirname, '../resources/sample.png'),
);
const imageData = await imageManager.loadImage(
path.join(__dirname, '../resources/transparent_sample.png'),
);
const cache = new Image(imageDataCache);
const image = new Image(imageData);
Object.assign(image, cache);
expect(image.width).toBe(180);
});

it('accepts a pre-loaded PNG instance', async () => {
const imageBuffer = load('sample.png');

const png = await new Promise((resolve: Function, reject: Function) => {
new PNG({ filterType: 4 }).parse(
imageBuffer,
(error: Error, data: PNG) => {
if (error) {
reject(error);
return;
}
resolve(data);
},
);
});

const image = new Image(png as PNG);
expect(image.width).toBe(180);
});
});
10 changes: 8 additions & 2 deletions __tests__/graphics/filter/BayerOrdered.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import * as path from 'path';
import { ImageManager } from 'escpos-buffer-image';
import { load } from '../../helper';
import { BayerOrdered, Image } from '../../../src';

describe('proccess images using Bayer ordered algorithm', () => {
it('apply filter on image from buffer', () => {
const image = new Image(load('sample.png'), new BayerOrdered());
it('apply filter on image from buffer', async () => {
const imageManager = new ImageManager();
const imageData = await imageManager.loadImage(
path.join(__dirname, '../../resources/sample.png'),
);
const image = new Image(imageData, new BayerOrdered());
expect(image.data).toStrictEqual(load('bayer_filter', image.data));
});
});
10 changes: 8 additions & 2 deletions __tests__/graphics/filter/FloydSteinberg.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import * as path from 'path';
import { ImageManager } from 'escpos-buffer-image';
import { load } from '../../helper';
import { FloydSteinberg, Image } from '../../../src';

describe('proccess images using Floyd and Steinberg algorithm', () => {
it('apply filter on image from buffer', () => {
const image = new Image(load('sample.png'), new FloydSteinberg());
it('apply filter on image from buffer', async () => {
const imageManager = new ImageManager();
const imageData = await imageManager.loadImage(
path.join(__dirname, '../../resources/sample.png'),
);
const image = new Image(imageData, new FloydSteinberg());
expect(image.data).toStrictEqual(
load('floyd_steinberg_filter', image.data),
);
Expand Down
10 changes: 8 additions & 2 deletions __tests__/graphics/filter/Threshold.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import * as path from 'path';
import { ImageManager } from 'escpos-buffer-image';
import { load } from '../../helper';
import { Threshold, Image } from '../../../src';

describe('proccess images using threshold algorithm', () => {
it('apply filter on image from buffer', () => {
const image = new Image(load('sample.png'), new Threshold());
it('apply filter on image from buffer', async () => {
const imageManager = new ImageManager();
const imageData = await imageManager.loadImage(
path.join(__dirname, '../../resources/sample.png'),
);
const image = new Image(imageData, new Threshold());
expect(image.data).toStrictEqual(load('threshold_filter', image.data));
});
});
19 changes: 17 additions & 2 deletions __tests__/profile/ControliD.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import InMemory from '../../src/connection/InMemory';
import Printer from '../../src/Printer';
import { Align, Style } from '../../src/actions';
import { load } from '../helper';
import { ImageManager } from 'escpos-buffer-image';

describe('controlid model profile', () => {
it('write bold text from model PrintiD', async () => {
Expand Down Expand Up @@ -42,9 +43,18 @@ describe('controlid model profile', () => {
);
});

it('draw qrcode from model PrintiD', async () => {
it('draw qrcode from model PrintiD without a image manager', async () => {
const connection = new InMemory();
const printer = await Printer.CONNECT('PrintiD', connection);
await expect(
printer.qrcode('https://github.com/grandchef/escpos-buffer'),
).rejects.toThrow('No image manager to draw qrcode');
});

it('draw qrcode from model PrintiD', async () => {
const connection = new InMemory();
const imageManager = new ImageManager();
const printer = await Printer.CONNECT('PrintiD', connection, imageManager);
await printer.setAlignment(Align.Center);
await printer.qrcode('https://github.com/grandchef/escpos-buffer');
await printer.setAlignment(Align.Left);
Expand All @@ -55,7 +65,12 @@ describe('controlid model profile', () => {

it('draw qrcode from model PrintiD Touch', async () => {
const connection = new InMemory();
const printer = await Printer.CONNECT('PrintiD-Touch', connection);
const imageManager = new ImageManager();
const printer = await Printer.CONNECT(
'PrintiD-Touch',
connection,
imageManager,
);
await printer.setAlignment(Align.Center);
await printer.qrcode('https://github.com/grandchef/escpos-buffer');
await printer.setAlignment(Align.Left);
Expand Down
10 changes: 8 additions & 2 deletions __tests__/profile/Daruma.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import * as path from 'path';
import { ImageManager } from 'escpos-buffer-image';
import InMemory from '../../src/connection/InMemory';
import Printer from '../../src/Printer';
import { Align, Style } from '../../src/actions';
Expand Down Expand Up @@ -49,8 +51,12 @@ describe('daruma model profile', () => {

it('draw picture from buffer from model DR800', async () => {
const connection = new InMemory();
const printer = await Printer.CONNECT('DR800', connection);
const image = new Image(load('sample.png'));
const imageManager = new ImageManager();
const printer = await Printer.CONNECT('DR800', connection, imageManager);
const imageData = await imageManager.loadImage(
path.join(__dirname, '../resources/sample.png'),
);
const image = new Image(imageData);
await printer.setAlignment(Align.Center);
await printer.draw(image);
await printer.setAlignment(Align.Left);
Expand Down
12 changes: 11 additions & 1 deletion __tests__/profile/Generic.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import InMemory from '../../src/connection/InMemory';
import Printer from '../../src/Printer';
import { Align, Style } from '../../src/actions';
import { load } from '../helper';
import { ImageManager } from 'escpos-buffer-image';

describe('generic model profile', () => {
it('write line text from model CMP-20', async () => {
Expand Down Expand Up @@ -39,9 +40,18 @@ describe('generic model profile', () => {
);
});

it('draw qrcode from model CMP-20', async () => {
it('draw qrcode from model CMP-20 without a image manager', async () => {
const connection = new InMemory();
const printer = await Printer.CONNECT('CMP-20', connection);
await expect(
printer.qrcode('https://github.com/grandchef/escpos-buffer'),
).rejects.toThrow('No image manager to draw qrcode');
});

it('draw qrcode from model CMP-20', async () => {
const connection = new InMemory();
const imageManager = new ImageManager();
const printer = await Printer.CONNECT('CMP-20', connection, imageManager);
await printer.setAlignment(Align.Center);
await printer.qrcode('https://github.com/grandchef/escpos-buffer');
await printer.setAlignment(Align.Left);
Expand Down
Binary file added __tests__/resources/transparent_sample.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 2 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "escpos-buffer",
"version": "3.1.0",
"version": "4.0.2",
"description": "Library to generate buffer for thermal printers.",
"author": "GrandChef Team <desenvolvimento@grandchef.com.br>",
"license": "MIT",
Expand Down Expand Up @@ -29,16 +29,14 @@
},
"dependencies": {
"iconv-lite": "^0.6.3",
"pngjs": "^5.0.0",
"qrcode": "^1.5.1",
"tslib": "^2.5.0"
},
"devDependencies": {
"@types/jest": "^29.4.0",
"@types/node": "^12.12.5",
"@types/pngjs": "^6.0.1",
"@types/w3c-web-usb": "1.0.6",
"@types/web-bluetooth": "^0.0.16",
"escpos-buffer-image": "^1.1.0",
"jest": "^29.4.1",
"prettier": "^2.8.3",
"rimraf": "^4.1.2",
Expand Down
5 changes: 4 additions & 1 deletion src/Printer.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import Model from './Model';
import { Connection } from './connection';
import Image from './graphics/Image';
import { StyleConf } from './profile';
import { Cut, Drawer, Align } from './actions';
import { SupportedModel } from './capabilities';
import Image from './graphics/Image';
import Manager from './graphics/Manager';

export default class Printer {
private model: Model;
Expand Down Expand Up @@ -84,6 +85,7 @@ export default class Printer {
static async CONNECT(
_model: SupportedModel | Model,
connection: Connection,
imageManager?: Manager,
): Promise<Printer> {
let model: Model;
if (typeof _model === 'string') {
Expand All @@ -93,6 +95,7 @@ export default class Printer {
}
await connection.open();
model.profile.connection = connection;
model.profile.imageManager = imageManager;
await model.profile.initialize();
return new Printer(model);
}
Expand Down
39 changes: 10 additions & 29 deletions src/graphics/Image.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,25 @@
import { Filter, FloydSteinberg } from './filter';
import * as fs from 'fs';
import { PNG } from 'pngjs';

export interface ImageData {
readonly data: Buffer;
readonly height: number;
readonly width: number;
}

export default class Image {
data: Buffer;
lines: number;
width: number;
bytesPerRow: number;

constructor(
input: string | Buffer | PNG = null,
filter: Filter = new FloydSteinberg(),
) {
if (input instanceof PNG) {
this.readImage(filter.process(input));
} else if (typeof input === 'string') {
this.loadImage(input, filter);
} else if (input) {
this.loadImageData(input, filter);
}
}

loadImage(filename: string, filter: Filter): void {
// tslint:disable-next-line: non-literal-fs-path
const data = fs.readFileSync(filename);
this.loadImageData(data, filter);
}

loadImageData(data: Buffer, filter: Filter): void {
const png = PNG.sync.read(data);
const image = filter.process(png);
this.readImage(image);
constructor(imageData: ImageData, filter: Filter = new FloydSteinberg()) {
this.readImage(filter.process(imageData));
}

/**
* Load actual image pixels from PNG image.
*
* @param image PNG image
* Load actual image pixels from image data.
*/
private readImage(image: PNG): void {
private readImage(image: ImageData): void {
const width = image.width;
const img_height = image.height;
const bits = 24;
Expand Down

0 comments on commit d602792

Please sign in to comment.