OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 17 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
17 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.ql;
15
 
16
import java.awt.image.BufferedImage;
17
import java.io.BufferedReader;
18
import java.io.ByteArrayOutputStream;
19
import java.io.DataOutputStream;
20
import java.io.File;
21
import java.io.IOException;
22
import java.io.InputStreamReader;
23
import java.net.InetAddress;
24
import java.net.Socket;
25
import java.net.UnknownHostException;
180 ilm 26
import java.nio.charset.StandardCharsets;
17 ilm 27
 
28
import javax.imageio.ImageIO;
29
 
30
public class QLPrinter {
180 ilm 31
    private static final int ESC = 0x1B;
17 ilm 32
    private String host;
33
    private boolean highQuality;
34
    private boolean paperCutAuto;
35
    private int printWidth;
36
    private int port = 515;
37
    private int timeout = 10000;
38
 
39
    public QLPrinter(String hostname) {
40
        if (hostname == null || hostname.trim().length() == 0) {
41
            throw new IllegalArgumentException("Bad HostName : " + hostname);
42
        }
43
        this.host = hostname;
44
        this.paperCutAuto = true;
45
        this.printWidth = 62;
46
    }
47
 
48
    public void setHighQuality(boolean b) {
49
        this.highQuality = b;
50
    }
51
 
52
    /**
53
     * Set print width (in milimeters)
180 ilm 54
     */
17 ilm 55
    public void setPrintWidth(int mm) {
56
        this.printWidth = mm;
57
    }
58
 
59
    public void setPaperCutAuto(boolean b) {
60
        this.paperCutAuto = b;
61
    }
62
 
63
    public void print(File f) throws IOException {
64
        BufferedImage img = ImageIO.read(f);
65
        print(img);
66
    }
67
 
68
    public void print(BufferedImage img) throws IOException {
69
        final byte data[] = getContent(img);
70
        print(data);
71
    }
72
 
73
    private byte[] getContent(BufferedImage img) {
74
        ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
75
        int nbLines = img.getHeight();
76
        int width = img.getWidth();
77
 
78
        // Header: 0x00 : 200 fois
79
        for (int i = 0; i < 200; i++) {
80
            out.write(0x00);
81
        }
180 ilm 82
 
83
        // Select ESCP/P Mode : 0x1B 0x69 0x61 0x01
84
        out.write(ESC);
17 ilm 85
        out.write(0x69);
86
        out.write(0x61);
87
        out.write(0x01);
180 ilm 88
        // Init 0x1B 0x40
89
        out.write(ESC);
90
        out.write(0x40);
91
 
17 ilm 92
        // Page Length
180 ilm 93
        out.write(ESC);
17 ilm 94
        out.write(0x69);
95
        out.write(0x7A);
96
 
97
        out.write(-58);
98
        out.write(10);
99
        out.write(this.printWidth);
100
        out.write(0);
101
 
102
        out.write(nbLines);
103
        out.write(nbLines >> 8);
104
        out.write(0);
105
        out.write(0);
106
        out.write(0);
107
        out.write(0);
180 ilm 108
        // Paper Cut : ESC i
109
        out.write(ESC);
17 ilm 110
        out.write(0x69);
111
        out.write(0x4D);
112
        if (this.paperCutAuto) {
113
            out.write(0x40);
114
        } else {
115
            out.write(0x00);
116
        }
117
 
180 ilm 118
        // ?? : 0x1B 0x69 0x41 0x01 :ESC i A
119
        out.write(ESC);
17 ilm 120
        out.write(0x69);
121
        out.write(0x41);
122
        out.write(0x01);
180 ilm 123
        // Set Mode : ESC i K
124
        out.write(ESC);
17 ilm 125
        out.write(0x69);
126
        out.write(0x4B);
127
        if (!this.highQuality) {
128
            out.write(0x08);
129
        } else {
130
            out.write(0x48);
131
        }
132
        // Set Margin
180 ilm 133
        out.write(ESC);
17 ilm 134
        out.write(0x69);
135
        out.write(0x64);
136
        out.write(0x00);
137
        out.write(0x00);
138
        // Set Compression
139
        out.write(0x4D);
140
        out.write(0x02);
141
 
142
        // Lines
143
        for (int i = 0; i < nbLines; i++) {
144
            int[] pixels = new int[width];
145
            img.getRGB(0, i, width, 1, pixels, 0, 4);
146
            try {
147
 
148
                final byte[] encodedLine = encodeLine(pixels);
149
                if (encodedLine.length > 1) {
150
                    out.write(0x67);
151
                    out.write(0);
152
                    out.write(encodedLine.length);
153
                }
154
                out.write(encodedLine);
155
 
156
            } catch (IOException e) {
157
                e.printStackTrace();
158
            }
159
        }
160
        // END
161
        out.write(0x1A);
162
 
163
        return out.toByteArray();
164
    }
165
 
166
    private byte[] encodeLine(int[] pixels) throws IOException {
167
        ByteArrayOutputStream out = new ByteArrayOutputStream(pixels.length);
168
        byte[] bytesToEncode = new byte[pixels.length / 8];
169
        int index = 0;
170
        for (int i = 0; i < bytesToEncode.length; i++) {
171
            int points = 0;
172
            for (int j = 0; j < 8; j++) {
173
                int c = pixels[pixels.length - index - 1];
174
                int r = (c & 0x00ff0000) >> 16;
175
                int g = (c & 0x0000ff00) >> 8;
176
                int b = c & 0x000000ff;
177
 
178
                int grayScale = (int) (21.2671 * r + 71.5160 * g + 7.2169 * b);
179
                boolean isBlack = grayScale < 12000;
180
 
181
                points = points * 2;
182
                if (isBlack) {
183
                    points++;
184
                }
185
                index++;
186
            }
187
            bytesToEncode[i] = (byte) points;
188
 
189
        }
190
 
191
        boolean emptyLine = true;
192
        for (int i = 0; i < bytesToEncode.length; i++) {
193
 
194
            if (bytesToEncode[i] != 0) {
195
                emptyLine = false;
196
                break;
197
            }
198
        }
199
 
200
        if (emptyLine) {
201
 
202
            out.write(0x5A);
203
        } else {
204
 
205
            ByteArrayOutputStream outTemp = new ByteArrayOutputStream();
206
            byte last = bytesToEncode[0];
207
            outTemp.write(last);
208
            boolean sameByteMode = false;
209
            for (int i = 1; i < bytesToEncode.length; i++) {
210
                byte b = bytesToEncode[i];
211
                if (b == last) {
212
                    if (sameByteMode) {
213
                        // On a le meme octet que ceux précédents
214
                        sameByteMode = true;
215
                        outTemp.write(b);
216
                    } else {
217
                        if (outTemp.size() > 1) {
218
                            // On encode en raw
219
                            send(out, outTemp.toByteArray(), sameByteMode);
220
                            // Nouvelle serie
221
                            outTemp = new ByteArrayOutputStream();
222
                            sameByteMode = false;
223
                        } else {
224
                            sameByteMode = true;
225
                        }
226
                        outTemp.write(b);
227
                    }
228
                } else {
229
                    if (sameByteMode) {
230
                        // On envoie la serie d'octets identiques
231
                        send(out, outTemp.toByteArray(), sameByteMode);
232
                        // Nouvelle serie
233
                        outTemp = new ByteArrayOutputStream();
234
                        sameByteMode = false;
235
                        outTemp.write(b);
236
                    } else {
237
                        sameByteMode = false;
238
                        outTemp.write(b);
239
 
240
                    }
241
                }
242
                if (outTemp.size() > 120) {
243
                    // On envoie la serie
244
                    send(out, outTemp.toByteArray(), sameByteMode);
245
                    // Nouvelle serie
246
                    outTemp = new ByteArrayOutputStream();
247
                    sameByteMode = false;
248
 
249
                }
250
                last = b;
251
            }
252
            if (outTemp.size() > 0) {
253
                // On envoie la serie
254
                send(out, outTemp.toByteArray(), sameByteMode);
255
            }
256
 
257
        }
258
        return out.toByteArray();
259
    }
260
 
261
    private void send(ByteArrayOutputStream out, byte[] byteArray, boolean sameByteMode) throws IOException {
262
        if (sameByteMode) {
263
            out.write(257 - byteArray.length);
264
            out.write(byteArray[0]);
265
        } else {
266
            out.write(byteArray.length - 1);
267
            out.write(byteArray);
268
        }
269
    }
270
 
271
    private String getNewJobId() {
272
        String id = String.valueOf((int) Math.floor(Math.random() * 999));
273
        while (id.length() < 3) {
274
            id = "0" + id;
275
        }
276
        return id;
277
    }
278
 
279
    public void print(byte data[]) throws UnknownHostException, IOException {
280
        final Socket socket = new Socket(InetAddress.getByName(this.host), this.port);
281
        socket.setSoTimeout(this.timeout);
282
        final String queue = "lpr";
283
        final String jobid = getNewJobId();
284
        if (socket != null) {
285
            String myHostName;
286
            try {
287
                myHostName = InetAddress.getLocalHost().getHostName();
288
            } catch (Exception e) {
289
                myHostName = "Host";
290
            }
291
            final String user = "Java";
292
            String cfa = getCFA(myHostName, user, "Label", jobid);
293
 
294
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
295
            DataOutputStream out = new DataOutputStream(socket.getOutputStream());
296
 
297
            // Init
298
            out.write(0x02);
299
            out.writeBytes(queue + "\n");
300
            out.flush();
301
            if (in.read() != 0) {
302
                throw new IOException("Error printing on queue");
303
            }
304
 
305
            // Control file
306
            out.write(0x02);
307
            out.writeBytes(String.valueOf(cfa.length()) + " ");
308
            out.writeBytes("cfA" + jobid + user + "\n");
309
            out.flush();
310
            if (in.read() != 0) {
311
                throw new IOException("Error sending start of control file");
312
            }
313
            out.writeBytes(cfa);
314
            out.writeByte(0x00);
315
            out.flush();
316
            if (in.read() != 0) {
317
                throw new IOException("Error sending control file");
318
            }
319
 
320
            // Data
321
            out.write(0x03);
322
            out.writeBytes(String.valueOf(data.length) + " ");
323
            out.writeBytes("dfA" + jobid + user + "\n");
324
            out.flush();
325
            if (in.read() != 0) {
326
                throw new IOException("Error sending start of data");
327
            }
328
            out.write(data);
329
            out.writeByte(0x00);
330
            out.flush();
331
            if (in.read() != 0) {
332
                throw new IOException("Error sending end of data");
333
            }
334
            out.flush();
335
 
336
            out.close();
337
            in.close();
338
            socket.close();
180 ilm 339
            System.out.println("QLPrinter.print() done");
17 ilm 340
        }
341
    }
342
 
343
    private String getCFA(String myHostName, String user, String documentName, String jobid) {
344
        String cfA = "";
345
        cfA += ("H" + myHostName + "\n");
346
        cfA += ("P" + user + "\n");
347
        cfA += ("J" + documentName + "\n");
348
        cfA += ("ldfA" + jobid + user + "\n");
349
        cfA += ("UdfA" + jobid + myHostName + "\n");
350
        cfA += ("N" + documentName + "\n");
351
        return cfA;
352
    }
353
 
180 ilm 354
    /**
355
     * Print 2D barcode (DataMatrix)
356
     *
357
     * @param dotsPerCell (3 - 10)
358
     * @param barcode : barcode (ascii)
359
     * @throws IOException
360
     *
361
     */
362
    public void printDataMatrixBarCode2D(int dotsPerCell, String barcode) throws IOException {
363
        if (barcode.length() > (144 * 144)) {
364
            throw new IllegalArgumentException("barcode too long (max : 144x144:20736)");
365
        }
366
 
367
        ByteArrayOutputStream out = new ByteArrayOutputStream();
368
        {
369
            // Header: 0x00 : 200 fois
370
            for (int i = 0; i < 200; i++) {
371
                out.write(0x00);
372
            }
373
 
374
        }
375
 
376
        // Select ESCP/P Mode : 0x1B 0x69 0x61 0x00
377
        out.write(ESC);
378
        out.write(0x69);
379
        out.write(0x61);
380
        out.write(0x00); // mode ESC/P standard
381
        // Init 0x1B 0x40
382
        out.write(ESC);
383
        out.write(0x40);
384
 
385
        // ESC i D
386
        out.write(ESC);
387
        out.write(0x69);
388
        out.write(0x44);
389
        //
390
        out.write(dotsPerCell);
391
        out.write(0); // square
392
        out.write(0); // vertical size : auto
393
        out.write(0); // horizontal size : auto
394
        for (int i = 0; i < 5; i++) {
395
            out.write(0); // reserved
396
        }
397
        // data
398
        out.write(barcode.getBytes(StandardCharsets.US_ASCII));
399
        out.write('\\');
400
        out.write('\\');
401
        out.write('\\');
402
        // Page feed
403
        out.write(0x0C);
404
 
405
        out.flush();
406
 
407
        final byte[] byteArray = out.toByteArray();
408
        print(byteArray);
409
    }
410
 
411
    public void print(String string) throws IOException {
412
        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
413
        // Select ESCP/P Mode : 0x1B 0x69 0x61 0x00
414
        bOut.write(ESC);
415
        bOut.write(0x69);
416
        bOut.write(0x61);
417
        bOut.write(0x0); // mode ESC/P standard
418
        // Init 0x1B 0x40
419
        bOut.write(ESC);
420
        bOut.write(0x40);
421
 
422
        // Init
423
        bOut.write(ESC);
424
        bOut.write(0x40);
425
        // French characters
426
        bOut.write(ESC);
427
        bOut.write(0x52);
428
        bOut.write(0x01);
429
        // Normal
430
        bOut.write(ESC);
431
        bOut.write(0x21);
432
        bOut.write(0);// Default
433
        bOut.write(string.getBytes(StandardCharsets.US_ASCII));
434
        bOut.write(0x0A);// Retour a la ligne
435
        // Page feed
436
        bOut.write(0x0C);
437
 
438
        print(bOut.toByteArray());
439
 
440
    }
441
 
17 ilm 442
}