@luckykiet/node-printer 1.0.0

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/lib/printer.js ADDED
@@ -0,0 +1,330 @@
1
+ var printer_helper = {},
2
+ fs = require("fs"),
3
+ child_process = require("child_process"),
4
+ os = require("os"),
5
+ path = require("path"),
6
+ binding_path = path.resolve(__dirname, './node_printer.node'),
7
+ printer_helper;
8
+
9
+ if(fs.existsSync(binding_path)) {
10
+ printer_helper = require(binding_path);
11
+ } else {
12
+ printer_helper = require('./node_printer_'+process.platform+'_'+process.arch+'.node');
13
+ }
14
+
15
+ /** Return all installed printers including active jobs
16
+ */
17
+ module.exports.getPrinters = getPrinters;
18
+
19
+ /** send data to printer
20
+ */
21
+ module.exports.printDirect = printDirect;
22
+
23
+ /// send file to printer
24
+ module.exports.printFile = printFile;
25
+
26
+ /** Get supported print format for printDirect
27
+ */
28
+ module.exports.getSupportedPrintFormats = printer_helper.getSupportedPrintFormats;
29
+
30
+ /**
31
+ * Get possible job command for setJob. It depends on os.
32
+ * @return Array of string. e.g.: DELETE, PAUSE, RESUME
33
+ */
34
+ module.exports.getSupportedJobCommands = printer_helper.getSupportedJobCommands;
35
+
36
+ /** get printer info object. It includes all active jobs
37
+ */
38
+ module.exports.getPrinter = getPrinter;
39
+ module.exports.getSelectedPaperSize = getSelectedPaperSize;
40
+ module.exports.getPrinterDriverOptions = getPrinterDriverOptions;
41
+
42
+ /// Return default printer name
43
+ module.exports.getDefaultPrinterName = getDefaultPrinterName;
44
+
45
+ /** get printer job info object
46
+ */
47
+ module.exports.getJob = getJob;
48
+ module.exports.setJob = setJob;
49
+
50
+ /**
51
+ * return user defined printer, according to https://www.cups.org/documentation.php/doc-2.0/api-cups.html#cupsGetDefault2 :
52
+ * "Applications should use the cupsGetDests and cupsGetDest functions to get the user-defined default printer,
53
+ * as this function does not support the lpoptions-defined default printer"
54
+ */
55
+ function getDefaultPrinterName() {
56
+ var printerName = printer_helper.getDefaultPrinterName();
57
+ if(printerName) {
58
+ return printerName;
59
+ }
60
+
61
+ // seems correct posix behaviour
62
+ var printers= getPrinters();
63
+ if(printers && printers.length){
64
+ var i = printers.length;
65
+ for(i in printers) {
66
+ var printer = printers[i];
67
+ if(printer.isDefault === true) {
68
+ return printer.name;
69
+ }
70
+ }
71
+ }
72
+
73
+ // printer not found, return nothing(undefined)
74
+ }
75
+
76
+ /** Get printer info with jobs
77
+ * @param printerName printer name to extract the info
78
+ * @return printer object info:
79
+ * TODO: to enum all possible attributes
80
+ */
81
+ function getPrinter(printerName)
82
+ {
83
+ if(!printerName) {
84
+ printerName = getDefaultPrinterName();
85
+ }
86
+ var printer = printer_helper.getPrinter(printerName);
87
+ correctPrinterinfo(printer);
88
+ return printer;
89
+ }
90
+
91
+ /** Get printer driver options includes advanced options like supported paper size
92
+ * @param printerName printer name to extract the info (default printer used if printer is not provided)
93
+ * @return printer driver info:
94
+ */
95
+ function getPrinterDriverOptions(printerName)
96
+ {
97
+ if(!printerName) {
98
+ printerName = getDefaultPrinterName();
99
+ }
100
+
101
+ return printer_helper.getPrinterDriverOptions(printerName);
102
+ }
103
+
104
+ /** Finds selected paper size pertaining to the specific printer out of all supported ones in driver_options
105
+ * @param printerName printer name to extract the info (default printer used if printer is not provided)
106
+ * @return selected paper size
107
+ */
108
+ function getSelectedPaperSize(printerName){
109
+ var driver_options = getPrinterDriverOptions(printerName);
110
+ var selectedSize = "";
111
+ if (driver_options && driver_options.PageSize) {
112
+ Object.keys(driver_options.PageSize).forEach(function(key){
113
+ if (driver_options.PageSize[key])
114
+ selectedSize = key;
115
+ });
116
+ }
117
+ return selectedSize;
118
+ }
119
+
120
+ function getJob(printerName, jobId)
121
+ {
122
+ return printer_helper.getJob(printerName, jobId);
123
+ }
124
+
125
+ function setJob(printerName, jobId, command)
126
+ {
127
+ return printer_helper.setJob(printerName, jobId, command);
128
+ }
129
+
130
+ function getPrinters(){
131
+ var printers = printer_helper.getPrinters();
132
+ if(printers && printers.length){
133
+ var i = printers.length;
134
+ for(i in printers){
135
+ correctPrinterinfo(printers[i]);
136
+ }
137
+ }
138
+ return printers;
139
+ }
140
+
141
+ function correctPrinterinfo(printer) {
142
+ if(printer.status || !printer.options || !printer.options['printer-state']){
143
+ return;
144
+ }
145
+
146
+ var status = printer.options['printer-state'];
147
+ // Add posix status
148
+ if(status == '3'){
149
+ status = 'IDLE'
150
+ }
151
+ else if(status == '4'){
152
+ status = 'PRINTING'
153
+ }
154
+ else if(status == '5'){
155
+ status = 'STOPPED'
156
+ }
157
+
158
+ // correct date type
159
+ var k;
160
+ for(k in printer.options) {
161
+ if(/time$/.test(k) && printer.options[k] && !(printer.options[k] instanceof Date)) {
162
+ printer.options[k] = new Date(printer.options[k] * 1000);
163
+ }
164
+ }
165
+
166
+ printer.status = status;
167
+ }
168
+
169
+ /*
170
+ print raw data. This function is intend to be asynchronous
171
+
172
+ parameters:
173
+ parameters - Object, parameters objects with the following structure:
174
+ data - String, mandatory, data to printer
175
+ printer - String, optional, name of the printer, if missing, will try to print to default printer
176
+ docname - String, optional, name of document showed in printer status
177
+ type - String, optional, only for wind32, data type, one of the RAW, TEXT
178
+ options - JS object with CUPS options, optional
179
+ success - Function, optional, callback function
180
+ error - Function, optional, callback function if exists any error
181
+
182
+ or
183
+
184
+ data - String, mandatory, data to printer
185
+ printer - String, optional, name of the printer, if missing, will try to print to default printer
186
+ docname - String, optional, name of document showed in printer status
187
+ type - String, optional, data type, one of the RAW, TEXT
188
+ options - JS object with CUPS options, optional
189
+ success - Function, optional, callback function with first argument job_id
190
+ error - Function, optional, callback function if exists any error
191
+ */
192
+ function printDirect(parameters){
193
+ var data = parameters
194
+ , printer
195
+ , docname
196
+ , type
197
+ , options
198
+ , success
199
+ , error;
200
+
201
+ if(arguments.length==1){
202
+ //TODO: check parameters type
203
+ //if (typeof parameters )
204
+ data = parameters.data;
205
+ printer = parameters.printer;
206
+ docname = parameters.docname;
207
+ type = parameters.type;
208
+ options = parameters.options||{};
209
+ success = parameters.success;
210
+ error = parameters.error;
211
+ }else{
212
+ printer = arguments[1];
213
+ type = arguments[2];
214
+ docname = arguments[3];
215
+ options = arguments[4];
216
+ success = arguments[5];
217
+ error = arguments[6];
218
+ }
219
+
220
+ if(!type){
221
+ type = "RAW";
222
+ }
223
+
224
+ // Set default printer name
225
+ if(!printer) {
226
+ printer = getDefaultPrinterName();
227
+ }
228
+
229
+ type = type.toUpperCase();
230
+
231
+ if(!docname){
232
+ docname = "node print job";
233
+ }
234
+
235
+ if (!options){
236
+ options = {};
237
+ }
238
+
239
+ //TODO: check parameters type
240
+ if(printer_helper.printDirect){// call C++ binding
241
+ try{
242
+ var res = printer_helper.printDirect(data, printer, docname, type, options);
243
+ if(res){
244
+ success(res);
245
+ }else{
246
+ error(Error("Something wrong in printDirect"));
247
+ }
248
+ }catch (e){
249
+ error(e);
250
+ }
251
+ }else{
252
+ error("Not supported");
253
+ }
254
+ }
255
+
256
+ /**
257
+ parameters:
258
+ parameters - Object, parameters objects with the following structure:
259
+ filename - String, mandatory, data to printer
260
+ docname - String, optional, name of document showed in printer status
261
+ printer - String, optional, mane of the printer, if missed, will try to retrieve the default printer name
262
+ success - Function, optional, callback function
263
+ error - Function, optional, callback function if exists any error
264
+ */
265
+ function printFile(parameters){
266
+ var filename,
267
+ docname,
268
+ printer,
269
+ options,
270
+ success,
271
+ error;
272
+
273
+ if((arguments.length !== 1) || (typeof(parameters) !== 'object')){
274
+ throw new Error('must provide arguments object');
275
+ }
276
+
277
+ filename = parameters.filename;
278
+ docname = parameters.docname;
279
+ printer = parameters.printer;
280
+ options = parameters.options || {};
281
+ success = parameters.success;
282
+ error = parameters.error;
283
+
284
+ if(!success){
285
+ success = function(){};
286
+ }
287
+
288
+ if(!error){
289
+ error = function(err){
290
+ throw err;
291
+ };
292
+ }
293
+
294
+ if(!filename){
295
+ var err = new Error('must provide at least a filename');
296
+ return error(err);
297
+ }
298
+
299
+ // try to define default printer name
300
+ if(!printer) {
301
+ printer = getDefaultPrinterName();
302
+ }
303
+
304
+ if(!printer) {
305
+ return error(new Error('Printer parameter of default printer is not defined'));
306
+ }
307
+
308
+ // set filename if docname is missing
309
+ if(!docname){
310
+ docname = filename;
311
+ }
312
+
313
+ //TODO: check parameters type
314
+ if(printer_helper.printFile){// call C++ binding
315
+ try{
316
+ // TODO: proper success/error callbacks from the extension
317
+ var res = printer_helper.printFile(filename, docname, printer, options);
318
+
319
+ if(!isNaN(parseInt(res))) {
320
+ success(res);
321
+ } else {
322
+ error(Error(res));
323
+ }
324
+ } catch (e) {
325
+ error(e);
326
+ }
327
+ } else {
328
+ error("Not supported");
329
+ }
330
+ }
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@luckykiet/node-printer",
3
+ "description": "Node.js native printer bindings. Fork of @thiagoelg/node-printer with Node 24+ support.",
4
+ "version": "1.0.0",
5
+ "homepage": "https://github.com/luckykiet/node-printer",
6
+ "author": {
7
+ "name": "Ion Lupascu",
8
+ "url": "http://program-support.co.uk/",
9
+ "email": "ionlupascu@gmail.com"
10
+ },
11
+ "contributors": [
12
+ "Thiago Lugli <thiagoelg@gmail.com>",
13
+ "Eko Eryanto <ekoeryanto@gmail.com>",
14
+ "luckykiet"
15
+ ],
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git://github.com/luckykiet/node-printer.git"
19
+ },
20
+ "devDependencies": {
21
+ "nodeunit": "*",
22
+ "prebuild": "^13.0.1",
23
+ "node-abi": "^4.26.0"
24
+ },
25
+ "engines": {
26
+ "node": ">= 20.0.0"
27
+ },
28
+ "scripts": {
29
+ "install": "prebuild-install || node-gyp rebuild",
30
+ "prebuild-all": "prebuild --all --force --strip --verbose",
31
+ "prebuild": "prebuild",
32
+ "rebuild": "node-gyp rebuild",
33
+ "test": "nodeunit test"
34
+ },
35
+ "binary": {
36
+ "module_name": "node_printer",
37
+ "module_path": "./lib/",
38
+ "host": "https://github.com/luckykiet/node-printer/releases/download/",
39
+ "remote_path": "v{version}"
40
+ },
41
+ "license": "MIT",
42
+ "main": "./lib/printer",
43
+ "dependencies": {
44
+ "nan": "^2.25.0",
45
+ "prebuild-install": "^7.1.3"
46
+ },
47
+ "types": "types/index.d.ts"
48
+ }
package/printer.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require('./lib/printer');
package/src/macros.hh ADDED
@@ -0,0 +1,159 @@
1
+ #ifndef NODE_PRINTER_SRC_MACROS_H
2
+ #define NODE_PRINTER_SRC_MACROS_H
3
+
4
+ #include <nan.h>
5
+ #include <node_version.h>
6
+
7
+ // NODE_MODULE_VERSION was incremented for v0.11
8
+
9
+ #if NODE_VERSION_AT_LEAST(0, 11, 10)
10
+ # define MY_NODE_MODULE_ISOLATE_DECL v8::Isolate* isolate = v8::Isolate::GetCurrent();
11
+ # define MY_NODE_MODULE_ISOLATE isolate
12
+ # define MY_NODE_MODULE_HANDLESCOPE MY_NODE_MODULE_ISOLATE_DECL Nan::HandleScope scope
13
+ # define V8_VALUE_NEW(type, value) v8::type::New(MY_NODE_MODULE_ISOLATE, value)
14
+ # define V8_VALUE_NEW_DEFAULT(type) v8::type::New(MY_NODE_MODULE_ISOLATE)
15
+ # if NODE_MODULE_VERSION > 73
16
+ # define V8_STRING_NEW_UTF8(value) v8::String::NewFromUtf8(MY_NODE_MODULE_ISOLATE, value).ToLocalChecked()
17
+ # define V8_STRING_NEW_2BYTES(value) v8::String::NewFromTwoByte(MY_NODE_MODULE_ISOLATE, value).ToLocalChecked()
18
+ # else
19
+ # define V8_STRING_NEW_UTF8(value) v8::String::NewFromUtf8(MY_NODE_MODULE_ISOLATE, value)
20
+ # define V8_STRING_NEW_2BYTES(value) v8::String::NewFromTwoByte(MY_NODE_MODULE_ISOLATE, value)
21
+ # endif
22
+
23
+ # define RETURN_EXCEPTION(msg) isolate->ThrowException(Nan::Error(msg)); \
24
+ return
25
+
26
+ # define RETURN_EXCEPTION_STR(msg) RETURN_EXCEPTION(V8_STRING_NEW_UTF8(msg))
27
+ # define MY_NODE_MODULE_RETURN_VALUE(value) iArgs.GetReturnValue().Set(value); \
28
+ return
29
+ # define MY_NODE_MODULE_RETURN_UNDEFINED() return
30
+ #else
31
+ # define MY_NODE_MODULE_ISOLATE_DECL
32
+ # define MY_NODE_MODULE_ISOLATE
33
+ # define MY_NODE_MODULE_HANDLESCOPE Nan::HandleScope scope;
34
+ # define V8_VALUE_NEW(type, value) v8::type::New(value)
35
+ # define V8_VALUE_NEW_DEFAULT(type) v8::type::New()
36
+ # define V8_STRING_NEW_UTF8(value) Nan::Utf8String(value)
37
+ # define V8_STRING_NEW_2BYTES(value) v8::String::New(value)
38
+
39
+ # define RETURN_EXCEPTION(msg) return v8::ThrowException(Nan::Error(msg))
40
+
41
+ # define RETURN_EXCEPTION_STR(msg) RETURN_EXCEPTION(V8_STRING_NEW_UTF8(msg))
42
+ # define MY_NODE_MODULE_RETURN_VALUE(value) return scope.Close(value)
43
+ # define MY_NODE_MODULE_RETURN_UNDEFINED() return scope.Close(v8::Undefined())
44
+ #endif
45
+
46
+ #if NODE_VERSION_AT_LEAST(4, 0, 0)
47
+ #define V8_LOCAL_STRING_FROM_VALUE(value) value->ToString(Nan::GetCurrentContext()).FromMaybe(v8::Local<v8::String>())
48
+ #define REQUIRE_ARGUMENT_INTEGER(args, i, var) \
49
+ int var; \
50
+ if (args[i]->IsInt32()) { \
51
+ var = args[i]->Int32Value(Nan::GetCurrentContext()).FromJust(); \
52
+ } \
53
+ else { \
54
+ RETURN_EXCEPTION_STR("Argument " #i " must be an integer"); \
55
+ }
56
+ #else
57
+ #define V8_LOCAL_STRING_FROM_VALUE(value) value->ToString()
58
+ #define REQUIRE_ARGUMENT_INTEGER(args, i, var) \
59
+ int var; \
60
+ if (args[i]->IsInt32()) { \
61
+ var = args[i]->Int32Value(); \
62
+ } \
63
+ else { \
64
+ RETURN_EXCEPTION_STR("Argument " #i " must be an integer"); \
65
+ }
66
+ #endif
67
+
68
+ #if NODE_VERSION_AT_LEAST(4, 0, 0)
69
+ #define MY_MODULE_SET_METHOD(exports, name, method) Nan::SetMethod(exports, name, method)
70
+ #define MY_NODE_MODULE_CALLBACK(name) void name(const Nan::FunctionCallbackInfo<v8::Value>& iArgs)
71
+ #else
72
+ #define MY_MODULE_SET_METHOD(exports, name, method) NODE_SET_METHOD(exports, name, method)
73
+ #define MY_NODE_MODULE_CALLBACK(name) void name(const v8::FunctionCallbackInfo<v8::Value>& iArgs)
74
+ #endif
75
+
76
+ #define V8_STR_CONC(left, right) \
77
+ v8::String::Concat(V8_STRING_NEW_UTF8(left), V8_STRING_NEW_UTF8(right))
78
+
79
+ #define REQUIRE_ARGUMENTS(args, n) \
80
+ if (args.Length() < (n)) { \
81
+ RETURN_EXCEPTION_STR("Expected " #n " arguments"); \
82
+ }
83
+
84
+
85
+ #define REQUIRE_ARGUMENT_EXTERNAL(i, var) \
86
+ if (args.Length() <= (i) || !args[i]->IsExternal()) { \
87
+ RETURN_EXCEPTION_STR("Argument " #i " invalid"); \
88
+ } \
89
+ v8::Local<v8::External> var = v8::Local<v8::External>::Cast(args[i]);
90
+
91
+ #define REQUIRE_ARGUMENT_OBJECT(args, i, var) \
92
+ if (args.Length() <= (i) || !args[i]->IsObject()) { \
93
+ RETURN_EXCEPTION_STR("Argument " #i " is not an object"); \
94
+ } \
95
+ v8::Local<v8::Object> var = v8::Local<v8::Object>::Cast(args[i]);
96
+
97
+
98
+ #define REQUIRE_ARGUMENT_FUNCTION(i, var) \
99
+ if (args.Length() <= (i) || !args[i]->IsFunction()) { \
100
+ RETURN_EXCEPTION_STR("Argument " #i " must be a function"); \
101
+ } \
102
+ v8::Local<v8::Function> var = v8::Local<v8::Function>::Cast(args[i]);
103
+
104
+
105
+ #define ARG_CHECK_STRING(args, i) \
106
+ if (args.Length() <= (i) || !args[i]->IsString()) { \
107
+ RETURN_EXCEPTION_STR("Argument " #i " must be a string"); \
108
+ } \
109
+
110
+ #define REQUIRE_ARGUMENT_STRING(args, i, var) \
111
+ ARG_CHECK_STRING(args, i); \
112
+ Nan::Utf8String var(V8_LOCAL_STRING_FROM_VALUE(args[i])); \
113
+
114
+ #if NODE_VERSION_AT_LEAST(12, 0, 0)
115
+ #define REQUIRE_ARGUMENT_STRINGW(args, i, var) \
116
+ ARG_CHECK_STRING(args, i); \
117
+ v8::String::Value var(MY_NODE_MODULE_ISOLATE, (args[i]));
118
+ #else
119
+ #define REQUIRE_ARGUMENT_STRINGW(args, i, var) \
120
+ ARG_CHECK_STRING(args, i); \
121
+ v8::String::Value var(V8_LOCAL_STRING_FROM_VALUE(args[i]));
122
+ #endif
123
+
124
+ #define OPTIONAL_ARGUMENT_FUNCTION(i, var) \
125
+ v8::Local<v8::Function> var; \
126
+ if (args.Length() > i && !args[i]->IsUndefined()) { \
127
+ if (!args[i]->IsFunction()) { \
128
+ RETURN_EXCEPTION_STR("Argument " #i " must be a function"); \
129
+ } \
130
+ var = v8::Local<v8::Function>::Cast(args[i]); \
131
+ }
132
+
133
+
134
+ #define OPTIONAL_ARGUMENT_INTEGER(args, i, var, default) \
135
+ int var; \
136
+ if (args.Length() <= (i)) { \
137
+ var = (default); \
138
+ } \
139
+ else if (args[i]->IsInt32()) { \
140
+ var = args[i]->Int32Value(Nan::GetCurrentContext()).FromJust(); \
141
+ } \
142
+ else { \
143
+ RETURN_EXCEPTION_STR("Argument " #i " must be an integer"); \
144
+ }
145
+ #define EMIT_EVENT(obj, argc, argv) \
146
+ TRY_CATCH_CALL((obj), \
147
+ Local<Function>::Cast((obj)->Get(String::NewSymbol("emit"))), \
148
+ argc, argv \
149
+ );
150
+
151
+ #define TRY_CATCH_CALL(context, callback, argc, argv) \
152
+ { TryCatch try_catch; \
153
+ (callback)->Call((context), (argc), (argv)); \
154
+ if (try_catch.HasCaught()) { \
155
+ FatalException(try_catch); \
156
+ } \
157
+ }
158
+
159
+ #endif
@@ -0,0 +1,41 @@
1
+ #include "node_printer.hpp"
2
+
3
+ #include <node_buffer.h>
4
+
5
+ NAN_MODULE_INIT(Init) {
6
+ // only for node
7
+ MY_MODULE_SET_METHOD(target, "getPrinters", getPrinters);
8
+ MY_MODULE_SET_METHOD(target, "getDefaultPrinterName", getDefaultPrinterName);
9
+ MY_MODULE_SET_METHOD(target, "getPrinter", getPrinter);
10
+ MY_MODULE_SET_METHOD(target, "getPrinterDriverOptions", getPrinterDriverOptions);
11
+ MY_MODULE_SET_METHOD(target, "getJob", getJob);
12
+ MY_MODULE_SET_METHOD(target, "setJob", setJob);
13
+ MY_MODULE_SET_METHOD(target, "printDirect", PrintDirect);
14
+ MY_MODULE_SET_METHOD(target, "printFile", PrintFile);
15
+ MY_MODULE_SET_METHOD(target, "getSupportedPrintFormats", getSupportedPrintFormats);
16
+ MY_MODULE_SET_METHOD(target, "getSupportedJobCommands", getSupportedJobCommands);
17
+ }
18
+
19
+ #if NODE_MAJOR_VERSION >= 10
20
+ NAN_MODULE_WORKER_ENABLED(node_printer, Init)
21
+ #else
22
+ NODE_MODULE(node_printer, Init)
23
+ #endif
24
+
25
+ // Helpers
26
+
27
+ bool getStringOrBufferFromV8Value(v8::Local<v8::Value> iV8Value, std::string &oData)
28
+ {
29
+ if(iV8Value->IsString())
30
+ {
31
+ Nan::Utf8String data_str_v8(V8_LOCAL_STRING_FROM_VALUE(iV8Value));
32
+ oData.assign(*data_str_v8, data_str_v8.length());
33
+ return true;
34
+ }
35
+ if(iV8Value->IsObject() && node::Buffer::HasInstance(iV8Value))
36
+ {
37
+ oData.assign(node::Buffer::Data(iV8Value), node::Buffer::Length(iV8Value));
38
+ return true;
39
+ }
40
+ return false;
41
+ }