-
Notifications
You must be signed in to change notification settings - Fork 18
/
PrinterConvert.c
4514 lines (4255 loc) · 189 KB
/
PrinterConvert.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <limits.h>
#include <unistd.h>
#include <png.h>
#include <setjmp.h>
#include "/usr/include/hpdf.h"
#include "/usr/include/SDL/SDL.h"
#include "dir.c"
const char* version = "v1.10";
/* Conversion program to convert Epson ESC/P printer data to an Adobe PDF file on Linux.
* v1.10
*
* v1.0 First Release - taken from the conversion software currently in development for the Retro-Printer module.
* v1.1 Swithced to using libHaru library to create the PDF file for speed and potential future enhancements - see http://libharu.org/
* Tidied up handling of the default configuration files
* v1.2 Removed possibility of a stack dump where tries to unlink both imagememory and seedrow
* v1.3 General code tidy and improve handling of 9 pin printers
* v1.4 Added Auto-Linefeed configuration, handle extended control codes and bring up to the same standard as v3.2 Retro-Printer Software
* v1.5 Speed improvements
* v1.6 Minor changes to instructions and set up INPUT_FILENAME as a definition
* v1.6.1 Changed usage instructions
* v1.6.2 Minor bug fix to the use of letter quality
* v1.6.3 Improve read_byte_from_file() as fseek and ftell not required (were needed for Retro-Printer Module implementation)
* Improve comments on MSB Setting to clarify usage
* v1.6.4 - 8 bit characters are enabled by default (for international character sets for example) - you can change this by setting use8bitchars = 0
* - If you want to use the top range of characters as italics, set useItalicsCharSet to 1
* - Default margins for A4 paper sizes are now 10 mm each side and 20 mm on the left (portrait) or the top (landscape)
* - The name of the file to be converted can be passed on the command line as last argument
* - read_byte_from_file() didn't manipulate the data but the address of the data
* - Superscript and subscript should look better now
* - Bug with unexpected infinite loop fixed
*
* v1.7 - Flexible command line control (see function usage() for more information)
* - Fix right margin issue (margin was ignored)
* - Load font data in one task calling fread()
* - Introduce quiet mode
* v1.8 - Fixed some errors in graphics printing and double height text
* v1.9 - Fixed potential errors with negative movements
* v1.10- Fixed errors in the Delta Row Printing Mode
*
* www.retroprinter.com
*
* Relies on libpng and ImageMagick libraries
*
* Incoming data (if Epson ESC/P or ESC/P2) is used to generate a bitmap.
* Without any library to convert the bitmap directly to PDF, we have to convert the bitmap to PNG initially and then
* convert the PNG to a PDF file using the libHaru library
*/
// START OF CONFIGURATION OPTIONS
// Configuration files - these are simple files with flags
#define LINEFEED_CONFIG "/root/config/linefeed_ending" // Unix, Windows or Mac line feeds in conversion
#define PATH_CONFIG "/root/config/output_path" // default path for output files
int cpi = 10; // PICA is standard
int pitch = 10; //Same as cpi but will retain its value when condensed printing is switched on
int needles = 24; // number of needles - 9 pin can be important for line spacing
int letterQuality = 0; // LQ Mode?
int proportionalSpacing = 0; // Proportional Mode (not implemented)
int imageMode = 1; // Whether to use faster in memory conversion or file conversion
int colourSupport = 6; // Does the ESC.2 / ESC.3 mode support 4 colour (CMYK) or 6 colour (CMYK + Light Cyan, Light Magenta) ?
int auto_LF = 0; // Whether we should process a CR on its own as a line feed
int step = 0;
// END OF CONFIGURATION OPTIONS
int use8bitchars = 0; // Use 8 bit character sets - for example for umlaut characters ASCII 160-255 are treated as normal characters (see Italics too)
int useItalicsCharSet = 0; // Whether characters with codes ASCII 160-255 are to be treated as italics (do not use with use8bitchars)
int quiet_mode = 0;
int pageSetWidth;
int pageSetHeight;
const float printerdpih = 720.0;
const float printerdpiv = 720.0;
float hmi = (float) 720 * ((float) 36 / (float) 360); // pitch in inches per character. Default is 36/360 * 720 = 10 cpi
int line_spacing = (float) 720 * ((float) 1 / (float) 6); // normally 1/6 inch line spacing - (float) 30*((float)pitch/(float)cpi);
int cdpih = 120; // fixed dots per inch used for printing characters
int cdpiv = 144; // fixed dots per inch used for printing characters
int cpih = 10; // Default is PICA
int cpiv = 6; // Default font height in cpi (default line spacing is 1/6" inch too)
int dpih = 180, dpiv = 180; // resolution in dpi for ESC/P2 printers
// Space used for storage - printermemory holds the bitmap file generated from the captured data
// seedrow is used for enhanced ESC/P2 printer modes where each line is based on preceding line
// imagememory is used to store the PNG file (generated from the bitmap).
unsigned char *printermemory, *seedrow, *imagememory;
int defaultMarginLeftp,defaultMarginRightp,defaultMarginTopp,defaultMarginBottomp;
int marginleft = 0, marginright = 99; // in characters
int marginleftp, marginrightp; // in pixels
int margintopp, marginbottomp;
unsigned int page = 0;
char filenameX[1000];
char filenameY[1000];
int xdim, ydim;
int sdlon = 0; // sdlon=1 Copy output to SDL screen
int state = 1; // State of the centronics interface
int countcharz;
char path[1000]; // main path
char pathraw[1000]; //path to raw files
char pathpng[1000]; //path to png files
char pathpdf[1000]; //path to pdf files
char patheps[1000]; //path to eps files
// colour table for quick lookup to convert printer colours to RGB
char red[129], green[129], blue[129];
int WHITE = 128; // Bit 7 is set for a white pixel in printermemory
int t1=0,t2=0,t3=0,t4=0,t5=0;
int ackposition = 0;
int msbsetting = 0;
int outputFormatText = 0; //Used to determine whether to convert line endings in captured file 0=no conversion 1=Unix (LF) 2= Windows (CR+LF) 3=MAC (CR)
int printColour = 0; //Default colour is black
double defaultUnit = 0; //Use Default defined unit
double thisDefaultUnit = 0; //Default unit for use by command
double pageManagementUnit = 0; //Default Page Management Unit - extended ESC ( U
double relHorizontalUnit = 0; //Default Relative Horizontal Management Unit - extended ESC ( U
double absHorizontalUnit = 0; //Default Absolute Horizontal Management Unit - extended ESC ( U
double relVerticalUnit = 0; //Default Relative Vertical Management Unit - extended ESC ( U
double absVerticalUnit = 0; //Default Absolute Vertical Management Unit - extended ESC ( U
int useExtendedSettings = 0; //Do we use normal settings for default unit or extended set?
int bold = 0; //Currently bold and double-strike are the same
int underlined = 0;
int italic = 0;
int superscript = 0;
int subscript = 0;
int strikethrough = 0;
int overscore = 0;
int double_width = 0; //Double width printing
int double_width_single_line = 0;
int double_height = 0; //Double height printing
int quad_height = 0; // 4 x Height Printing - Star NL-10
int outline_printing = 0; //Outline printing not yet implemeneted
int shadow_printing = 0; //Shadow printing not yet implemented
int print_controlcodes = 0;
int print_uppercontrolcodes= 0;
int graphics_mode = 0;
int microweave_printing = 0;
int multipoint_mode = 0;
int escKbitDensity = 0; // 60 dpi
int escLbitDensity = 1; // 120 dpi
int escYbitDensity = 2; // 120 dpi
int escZbitDensity = 3; // 240 dpi
SDL_Surface *display;
jmp_buf env;
FILE *inputFile;
int isNthBitSet (unsigned char c, int n) {
return (c >> n) & 1;
}
// CMYK Colour mixing method
double * rgb_to_cmyk(int rgb_red, int rgb_green, int rgb_blue)
{
static double cmyk_value[4];
double rgb_scale = 255, cmyk_scale = 100, min_cmy;
cmyk_value[0] = 0;
cmyk_value[1] = 0;
cmyk_value[2] = 0;
cmyk_value[3] = 0;
if ((rgb_red == 0) && (rgb_green == 0) && (rgb_blue == 0)) {
// black
return cmyk_value;
}
// Change rgb [0,255] -> cmy [0,1]
cmyk_value[0] = 1 - ((double) rgb_red / rgb_scale);
cmyk_value[1] = 1 - ((double) rgb_green / rgb_scale);
cmyk_value[2] = 1 - ((double) rgb_blue / rgb_scale);
// extract out k [0,1]
min_cmy = cmyk_value[0];
if (cmyk_value[1] < min_cmy) min_cmy = cmyk_value[1];
if (cmyk_value[2] < min_cmy) min_cmy = cmyk_value[2];
cmyk_value[0] = (cmyk_value[0] - min_cmy);
cmyk_value[1] = (cmyk_value[1] - min_cmy);
cmyk_value[2] = (cmyk_value[2] - min_cmy);
cmyk_value[3] = min_cmy;
// rescale to the range [0,cmyk_scale]
cmyk_value[0] = cmyk_value[0] * cmyk_scale;
cmyk_value[1] = cmyk_value[1] * cmyk_scale;
cmyk_value[2] = cmyk_value[2] * cmyk_scale;
cmyk_value[3] = cmyk_value[3] * cmyk_scale;
return cmyk_value;
}
int * cmyk_to_rgb(double cmyk_c, double cmyk_m, double cmyk_y, double cmyk_k)
{
static int rgb_value[3]; // test
double rgb_scale = 255, cmyk_scale = 100;
rgb_value[0] = rgb_scale*(1.0-(cmyk_c+cmyk_k)/cmyk_scale);
rgb_value[1] = rgb_scale*(1.0-(cmyk_m+cmyk_k)/cmyk_scale);
rgb_value[2] = rgb_scale*(1.0-(cmyk_y+cmyk_k)/cmyk_scale);
return rgb_value;
}
int * cmykColourMix(int rgb_red1, int rgb_green1, int rgb_blue1, int rgb_red2, int rgb_green2, int rgb_blue2)
{
static int rgb_result[3];
int *rgb_lookups;
double *cmyk, cmyk_result_c, cmyk_result_m, cmyk_result_y, cmyk_result_k, opacity = 0.5;
cmyk_result_c = 0;
cmyk_result_m = 0;
cmyk_result_y = 0;
cmyk_result_k = 0;
cmyk = rgb_to_cmyk(rgb_red1, rgb_green1, rgb_blue1);
cmyk_result_c += opacity * cmyk[0];
cmyk_result_m += opacity * cmyk[1];
cmyk_result_y += opacity * cmyk[2];
cmyk_result_k += opacity * cmyk[3];
cmyk = rgb_to_cmyk(rgb_red2, rgb_green2, rgb_blue2);
cmyk_result_c += opacity * cmyk[0];
cmyk_result_m += opacity * cmyk[1];
cmyk_result_y += opacity * cmyk[2];
cmyk_result_k += opacity * cmyk[3];
rgb_lookups = cmyk_to_rgb(cmyk_result_c, cmyk_result_m, cmyk_result_y, cmyk_result_k);
rgb_result[0] = rgb_lookups[0];
rgb_result[1] = rgb_lookups[1];
rgb_result[2] = rgb_lookups[2];
return rgb_result;
}
int * lookupColour(unsigned char colourValue)
{
// Convert printer colour (0 to 7 stored in bits of colourValue) to RGB value
// Routine uses averaging to get colours such as pink (red + white)
static int rgb1[3];
int colourMixMethod = 2; // 1 = RGB simple addition method, 2 = Standard CMYK Mix with conversion -
int *mixedColour;
int mixedColour_red, mixedColour_green, mixedColour_blue;
rgb1[0]=0;
rgb1[1]=0;
rgb1[2]=0;
if (colourValue == 1) return rgb1; // Black
int mixColour = 0;
if (colourValue == 0 || colourValue == WHITE) {
// Bit 7 is set for white - not supported on printers
rgb1[0]=255;
rgb1[1]=255;
rgb1[2]=255;
return rgb1;
}
if (isNthBitSet(colourValue, 0) ) {
// Black - default
mixColour = 1;
}
mixedColour_red = rgb1[0];
mixedColour_green = rgb1[1];
mixedColour_blue = rgb1[2];
if (isNthBitSet(colourValue, 1) ) {
// Magenta FF00FF
if (mixColour == 1) {
if (colourMixMethod == 1) {
mixedColour_red = (mixedColour_red + 255) /2;
mixedColour_green = (mixedColour_green + 0) /2;
mixedColour_blue = (mixedColour_blue + 255) /2;
} else {
mixedColour = cmykColourMix(mixedColour_red, mixedColour_green, mixedColour_blue, 255, 0, 255);
mixedColour_red = mixedColour[0];
mixedColour_green = mixedColour[1];
mixedColour_blue = mixedColour[2];
}
} else {
mixedColour_red = 255;
mixedColour_green = 0;
mixedColour_blue = 255;
}
mixColour = 1;
}
if (isNthBitSet(colourValue, 2) ) {
// Cyan 00FFFF
if (mixColour == 1) {
if (colourMixMethod == 1) {
mixedColour_red = (mixedColour_red + 0) /2;
mixedColour_green = (mixedColour_green + 255) /2;
mixedColour_blue = (mixedColour_blue + 255) /2;
} else {
mixedColour = cmykColourMix(mixedColour_red, mixedColour_green, mixedColour_blue, 0, 255, 255);
mixedColour_red = mixedColour[0];
mixedColour_green = mixedColour[1];
mixedColour_blue = mixedColour[2];
}
} else {
mixedColour_red = 0;
mixedColour_green = 255;
mixedColour_blue = 255;
}
mixColour = 1;
}
if (isNthBitSet(colourValue, 3) ) {
// Violet EE82EE
if (mixColour == 1) {
if (colourMixMethod == 1) {
mixedColour_red = (mixedColour_red + 238) /2;
mixedColour_green = (mixedColour_green + 130) /2;
mixedColour_blue = (mixedColour_blue + 238) /2;
} else {
mixedColour = cmykColourMix(mixedColour_red, mixedColour_green, mixedColour_blue, 238, 130, 238);
mixedColour_red = mixedColour[0];
mixedColour_green = mixedColour[1];
mixedColour_blue = mixedColour[2];
}
} else {
mixedColour_red = 238;
mixedColour_green = 130;
mixedColour_blue = 238;
}
mixColour = 1;
}
if (isNthBitSet(colourValue, 4) ) {
// Yellow FFFF00
if (mixColour == 1) {
if (colourMixMethod == 1) {
mixedColour_red = (mixedColour_red + 255) /2;
mixedColour_green = (mixedColour_green + 255) /2;
mixedColour_blue = (mixedColour_blue + 0) /2;
} else {
mixedColour = cmykColourMix(mixedColour_red, mixedColour_green, mixedColour_blue, 255, 255, 0);
mixedColour_red = mixedColour[0];
mixedColour_green = mixedColour[1];
mixedColour_blue = mixedColour[2];
}
} else {
mixedColour_red = 255;
mixedColour_green = 255;
mixedColour_blue = 0;
}
mixColour = 1;
}
if (isNthBitSet(colourValue, 5) ) {
// Red FF0000
if (mixColour == 1) {
if (colourMixMethod == 1) {
mixedColour_red = (mixedColour_red + 255) /2;
mixedColour_green = (mixedColour_green + 0) /2;
mixedColour_blue = (mixedColour_blue + 0) /2;
} else {
mixedColour = cmykColourMix(mixedColour_red, mixedColour_green, mixedColour_blue, 255, 0, 0);
mixedColour_red = mixedColour[0];
mixedColour_green = mixedColour[1];
mixedColour_blue = mixedColour[2];
}
} else {
mixedColour_red = 255;
mixedColour_green = 0;
mixedColour_blue = 0;
}
mixColour = 1;
}
if (isNthBitSet(colourValue, 6) ) {
// Green 00FF00
if (mixColour == 1) {
if (colourMixMethod == 1) {
mixedColour_red = (mixedColour_red + 0) /2;
mixedColour_green = (mixedColour_green + 255) /2;
mixedColour_blue = (mixedColour_blue + 0) /2;
} else {
mixedColour = cmykColourMix(mixedColour_red, mixedColour_green, mixedColour_blue, 0, 255, 0);
mixedColour_red = mixedColour[0];
mixedColour_green = mixedColour[1];
mixedColour_blue = mixedColour[2];
}
} else {
mixedColour_red = 0;
mixedColour_green = 255;
mixedColour_blue = 0;
}
}
/* For CMYKlMlC printing we have to support 10 bits - not implemented as it would double memory used for only a small subset of later printers
If necessary, would be better to have flag to say if 6 colour printing desired (although some large format printers support 8 colours)
and could then renumber the bits and use WHITE = 0
if (isNthBitSet(colourValue, 9) ) {
// Light Magenta FF80FF
if (mixColour == 1) {
if (colourMixMethod == 1) {
mixedColour_red = (mixedColour_red + 255) /2;
mixedColour_green = (mixedColour_green + 128) /2;
mixedColour_blue = (mixedColour_blue + 255) /2;
} else {
mixedColour = cmykColourMix(mixedColour_red, mixedColour_green, mixedColour_blue, 255, 128, 255);
mixedColour_red = mixedColour[0];
mixedColour_green = mixedColour[1];
mixedColour_blue = mixedColour[2];
}
} else {
mixedColour_red = 255;
mixedColour_green = 128;
mixedColour_blue = 255;
}
mixColour = 1;
}
if (isNthBitSet(colourValue, 10) ) {
// Light Cyan 80FFFF
if (mixColour == 1) {
if (colourMixMethod == 1) {
mixedColour_red = (mixedColour_red + 128) /2;
mixedColour_green = (mixedColour_green + 255) /2;
mixedColour_blue = (mixedColour_blue + 255) /2;
} else {
mixedColour = cmykColourMix(mixedColour_red, mixedColour_green, mixedColour_blue, 128, 255, 255);
mixedColour_red = mixedColour[0];
mixedColour_green = mixedColour[1];
mixedColour_blue = mixedColour[2];
}
} else {
mixedColour_red = 128;
mixedColour_green = 255;
mixedColour_blue = 255;
}
}
*/
rgb1[0] = mixedColour_red;
rgb1[1] = mixedColour_green;
rgb1[2] = mixedColour_blue;
return rgb1;
}
void setupColourTable()
{
// Create a lookup table to look up all of the possible colour combinations and convert to RGB for quicker PNG generation
int j, *pixelColour;
for (j = 0; j<=128; j++) {
pixelColour = lookupColour(j);
red[j] = pixelColour[0];
green[j] = pixelColour[1];
blue[j] = pixelColour[2];
}
}
void erasepage()
{
//clear memory
memset(printermemory, WHITE , pageSetWidth * pageSetHeight);
}
int initialize(const char* input_filename)
{
// Choose PNG Generation mode - 1 = in memory (fast but uses a lot more memory), 2 = use external file (slower, but less memory)
imageMode = 1;
marginleftp = defaultMarginLeftp;
marginrightp = defaultMarginRightp; // in pixels
margintopp = defaultMarginTopp;
marginbottomp = defaultMarginBottomp;
// Set aside enough memory to store the parsed image
printermemory = malloc ((pageSetWidth+1) * pageSetHeight);
if (printermemory == NULL) {
fputs("Can't allocate memory for Printer Conversion.\n", stderr);
exit (1);
}
// For Delta Row compression - set aside room to store 4 seed rows (1 per supported colour)
if (imageMode == 1 ) {
// Faster method of creating and converting PNG image - stores it in memory, so needs a lot more memory
imagememory = calloc (3 * (pageSetWidth+1) * pageSetHeight, 1);
if (imagememory == NULL) {
free(printermemory);
printermemory=NULL;
fputs("Can't allocate memory for PNG image.\n", stderr);
exit (1);
}
// For Delta Row compression - set aside room to store colourSupport (4 or 6) seed rows (1 per supported colour)
// May as well use the imagememory temporarily for the seedrows
seedrow = imagememory;
} else {
// Slower method - PNG image is saved to disk first and then converted from there
seedrow = calloc ((pageSetWidth+1) * colourSupport, 1);
if (seedrow == NULL) {
free(printermemory);
printermemory=NULL;
fputs("Can't allocate memory for Delta Row Printing.\n", stderr);
exit (1);
}
}
erasepage();
setupColourTable();
/* routine could be used here to open the input file or port for reading
* example is for reading from an input file called ./Test1.prn
* The routine is not error trapped at present
*/
inputFile = fopen(input_filename, "r");
if (inputFile == NULL)
{
fprintf(stderr, "Failed to open input file: '%s'\n", input_filename);
return -1;
}
}
int read_byte_from_file (char *xd)
{
// This needs to be written to read each byte from specified file
*xd=fgetc(inputFile);
switch (msbsetting) {
case 0:
// No change
break;
case 1:
// MSB setting clears bit 7
*xd = (int) *xd & 127;
break;
case 2:
// MSB setting forces bit 7 to 1
*xd = (int) *xd | 128;
break;
}
return feof(inputFile) ? 0 : -1;
}
/*
* Check if a file exist using stat() function
* return 1 if the file exist otherwise return 0
*/
int cfileexists(const char* filename)
{
struct stat buffer;
return (stat (filename, &buffer) == 0);
}
int write_png(const char *filename, int width, int height, char *rgb)
{
int ipos, data_found = 0, end_loop = 0;
unsigned char pixelColour;
int code = 1;
//Used only if (imageMode == 2 )
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
png_bytep row = NULL;
//
FILE *file = NULL;
// Check if a blank page - if so ignore it!
int x, y, ppos;
for (y=0 ; y<height && !data_found; y++) {
ipos = width * y;
for (x=0 ; x<width && !data_found; x++) {
if (rgb[ipos+x] != WHITE) data_found = 1;
}
}
if (!data_found) return 0; // Nothing to print
if (imageMode == 1 ) {
// Create raw image in memory for speed
// Write image data - 8 bit RGB
// Create raw image in memory
ppos=0;
for (y=0 ; y<height ; y++) {
ipos = width * y;
for (x=0 ; x<width ; x++) {
pixelColour = rgb[ipos + x];
imagememory[ppos++] = red[pixelColour];
imagememory[ppos++] = green[pixelColour];
imagememory[ppos++] = blue[pixelColour];
}
}
} else {
// Use LibPNG to create a PNG image on disk for conversion
if (!quiet_mode) printf("write = %s \n", filenameX);
// Open file for writing (binary mode)
file = fopen(filename, "wb");
if (file == NULL) {
fprintf(stderr, "PNG error - Could not open file %s for writing\n", filename);
code = 0;
goto finalise;
}
// Initialize write structure
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fputs("PNG error - Could not allocate write structure\n", stderr);
code = 0;
goto finalise;
}
// Initialize info structure
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fputs("PNG error - Could not allocate info structure\n", stderr);
code = 0;
goto finalise;
}
png_set_compression_level(png_ptr, 6); // Minimal compression for speed - balance against time taken by convert routine
// Setup Exception handling
if (setjmp(png_jmpbuf(png_ptr))) {
fputs("Error during png creation\n", stderr);
code = 0;
goto finalise;
}
png_init_io(png_ptr, file);
// Write header (8 bit colour depth)
png_set_IHDR(png_ptr, info_ptr, width, height,
8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
// Set the resolution of the image to 720dpi
png_set_pHYs(png_ptr, info_ptr, printerdpih/0.0254, printerdpiv/0.0254,
PNG_RESOLUTION_METER);
png_write_info(png_ptr, info_ptr);
// Allocate memory for a rows (3 bytes per pixel - 8 bit RGB)
row = (png_bytep) malloc(3 * width * sizeof(png_byte));
if (row == NULL) {
fputs("Can't allocate memory for PNG file.\n", stderr);
code = 0;
goto finalise;
}
// Write image data - 8 bit RGB
for (y=0 ; y<height ; y++) {
ipos = width * y;
ppos=0;
for (x=0 ; x<width ; x++) {
pixelColour = rgb[ipos + x];
row[ppos++] = red[pixelColour];
row[ppos++] = green[pixelColour];
row[ppos++] = blue[pixelColour];
}
png_write_row(png_ptr, row);
}
// End write
png_write_end(png_ptr, NULL);
}
finalise:
if (imageMode == 1 ) {
// No need to free up memory - will reuse existing memory
} else {
// Tidy up LibPNG accesses
if (file != NULL) fclose(file);
if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
if (row != NULL) free(row);
}
return code;
}
void pdf_error_handler (HPDF_STATUS error_no, HPDF_STATUS detail_no, void *user_data)
{
fprintf(stderr, "ERROR: error_no=%04X, detail_no=%u\n", (HPDF_UINT)error_no, (HPDF_UINT)detail_no);
longjmp(env, 1);
}
HPDF_REAL ScaleDPI(HPDF_REAL size)
{
return (float) size * (72.0F / (float) printerdpih);
}
int write_pdf (const char *filename, const char *pdfname, int width, int height)
{
HPDF_Doc pdf;
HPDF_Font font;
HPDF_Page page;
HPDF_Destination dst;
pdf = HPDF_New (pdf_error_handler, NULL);
if (!pdf) {
fputs("error: cannot create PdfDoc object\n", stderr);
return 1;
}
/* error-handler */
if (setjmp(env)) {
HPDF_Free (pdf);
return 1;
}
HPDF_SetCompressionMode (pdf, HPDF_COMP_ALL);
/* create default-font */
font = HPDF_GetFont (pdf, "Helvetica", NULL);
/* add a new page object. */
page = HPDF_AddPage (pdf);
HPDF_Page_SetWidth (page, ScaleDPI(width));
HPDF_Page_SetHeight (page, ScaleDPI(height));
dst = HPDF_Page_CreateDestination (page);
HPDF_Destination_SetXYZ (dst, 0, HPDF_Page_GetHeight (page), 1);
HPDF_SetOpenAction(pdf, dst);
/*
HPDF_Page_BeginText (page);
HPDF_Page_SetFontAndSize (page, font, 20);
HPDF_Page_MoveTextPos (page, 220, HPDF_Page_GetHeight (page) - 70);
HPDF_Page_ShowText (page, "PngDemo");
HPDF_Page_EndText (page);
HPDF_Page_SetFontAndSize (page, font, 12);
*/
HPDF_Image image;
if (imageMode == 1 ) {
image = HPDF_LoadRawImageFromMem (pdf, imagememory,
width, height, HPDF_CS_DEVICE_RGB, 8);
} else {
image = HPDF_LoadPngImageFromFile (pdf, filename);
}
/* Draw image to the canvas. */
HPDF_Page_DrawImage (page, image, 0, 0, ScaleDPI(width),
ScaleDPI(height));
/* save the document to a file */
HPDF_SaveToFile (pdf, pdfname);
/* clean up */
HPDF_Free (pdf);
return 0;
}
void putpx(int x, int y)
{
// Write printer colour to specific pixel on the created bitmap
int pos = y * pageSetWidth + x;
unsigned char existingPixel = printermemory[pos];
// If existing pixel is white, then we need to reset it to 0 before OR'ing the chosen colour
if (existingPixel == WHITE) {
printermemory[pos] = (1 << printColour);
} else {
printermemory[pos] |= (1 << printColour);
}
}
/*
* Set the pixel at (x, y) to the given value
* NOTE: The surface must be locked before calling this!
*/
static float divi = 1.0; // divider for lower resolution
void putpixel(SDL_Surface * surface, int x, int y, Uint32 pixel)
{
// if we are out of scope don't putpixel, otherwise we'll get a segmentation fault
if (x > (pageSetWidth - 1)) return;
if (y > (pageSetHeight - 1)) return;
putpx(x, y); // Plot to bitmap for PDF
if (sdlon == 0) return;
// Add pixel to the screen
x = x / divi;
y = y / divi;
if (x > xdim) return;
if (y > ydim) return;
int bpp = surface->format->BytesPerPixel;
// Here p is the address to the pixel we want to set
Uint8 *p = (Uint8 *) surface->pixels + y * surface->pitch + x * bpp;
// Convert the otherwise black pixel to the desired colour
if (pixel == 0x00000000) {
switch (printColour) {
case 0:
// Black
pixel = 0x00000000;
break;
case 1:
// Magenta
pixel = 0x00FF00FF;
break;
case 2:
// Cyan
pixel = 0x0000FFFF;
break;
case 3:
// Violet
pixel = 0x00EE82EE;
break;
case 4:
// Yellow
pixel = 0x00FFFF00;
break;
case 5:
// Red
pixel = 0x00FF0000;
break;
case 6:
// Green
pixel = 0x0000FF00;
break;
case 7:
// White
pixel = 0x00FFFFFF;
break;
}
}
// If existing pixel is 0x00FFFFFF (white), then we need to reset it to 0x00000000; before OR'ing the chosen colour
switch (bpp) {
case 1:
if (p[0] == 255) {
p[0] = pixel;
} else {
p[0] |= pixel;
}
break;
case 2:
if (p[0] == 255 && p[1] == 255) {
p[0] = pixel;
p[1] = pixel;
} else {
*(Uint16 *) p |= pixel;
}
break;
case 3:
if (p[0] == 255 && p[1] == 255 && p[2] == 255) {
p[0] = pixel;
p[1] = pixel;
p[2] = pixel;
} else if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
p[0] |= (pixel >> 16) & 0xff;
p[1] |= (pixel >> 8) & 0xff;
p[2] |= pixel & 0xff;
} else {
p[0] |= pixel & 0xff;
p[1] |= (pixel >> 8) & 0xff;
p[2] |= (pixel >> 16) & 0xff;
}
break;
case 4:
if (p[0] == 255 && p[1] == 255 && p[2] == 255 && p[3] == 255) {
*(Uint32 *) p = pixel;
} else {
*(Uint32 *) p |= pixel;
}
break;
}
}
void putpixelbig(int xpos, int ypos, int hwidth, int vdith)
{
int a, b;
for (a = 0; a < hwidth; a++) {
for (b = 0; b < vdith; b++) {
putpixel(display, xpos + a, ypos + b, 0x00000000);
}
}
}
int rows = 0;
int xpos = 0, ypos = 0; // position of print head
int xpos2 = 0, ypos2 = 0; // position of print head
float chrSpacing = 0; // Inter-character spacing
// ******bit images
int m; // Mode for bit images printing (m)
int m1, m2, m3, m4; // Used for extended commands
int c, v, h; // Used for raster graphics printing
unsigned char nL, nH; // width of bit image line, lowbyte and high byte
unsigned char mL, mH; // extra parameters mode, lowbyte and high byte
unsigned char tL, tH; // extra parameters top margin, lowbyte and high byte
unsigned char bL, bH; // extra parameters bottom margin, lowbyte and high byte
unsigned char d1, d2, d3;
unsigned char a0, a1, a2;
int advance; // Used to calculate negative movements
int dotColumns; // number of dot columns for bit images
// Tabs
double hTabulators[35]; // List of tabulators
double vTabulators[16 * 8]; // List of vertical tabulators
int vTabulatorsSet = 0; // Used by VT command to check if any vertical tabs have been set since printer reset
int vTabulatorsCancelled = 0; // Used by VT command to check if all vertical tabs have been cancelled
int vFUChannel = 0; // VFU Channel to use
int curHtab = 0; // next active horizontal tab
int curVtab = 0; // next active vertical tab
int hPixelWidth, vPixelWidth;
FILE *f;
FILE *fp = NULL;
#define FONT_SIZE 4096
char fontx[FONT_SIZE];
void erasesdl()
{
int i, t;
if (sdlon == 0) return;
// pageSetWidth*pageSetHeight
for (i = 0; i < pageSetWidth; i++) {
for (t = 0; t < pageSetHeight; t++) {
putpixel(display, i, t, 0x00FFFFFF);
}
}
}
int test_for_new_paper()
{
// if we are out of paper
if ((ypos < margintopp) || (ypos > marginbottomp) || (state == 0)) {
xpos = marginleftp;
ypos = margintopp;
sprintf(filenameX, "%spage%d.png", pathpng, page);
if (write_png(filenameX, pageSetWidth, pageSetHeight, printermemory) > 0) {
// Create pdf file
sprintf(filenameY, "%spage%d.pdf", pathpdf, page);
write_pdf(filenameX, filenameY, pageSetWidth, pageSetHeight);
erasesdl();
erasepage();
page++;
if (page > 199) {
page = dirX(pathraw);
reduce_pages(page, pathraw);
page = dirX(pathpng);
reduce_pages(page, pathpng);
page = dirX(pathpdf);
reduce_pages(page, pathpdf);
page = dirX(pathpdf) + 1;
}
}
if (fp != NULL) {
fclose(fp);
fp = NULL;
}
}
state = 1;
}
int precedingDot(int x, int y) {
int pos = (y * pageSetWidth) + (x-1);
if (printermemory[pos] == WHITE) return 0;
return 1;
}
void _clear_seedRow(int seedrowColour) {
// colourSupport seedrows - each pixel is represented by a bit.
if (seedrowColour > (colourSupport-1)) seedrowColour = colourSupport-1;
memset(seedrow + ((seedrowColour * pageSetWidth) /8), 0 , (pageSetWidth / 8));
}
void _print_seedRows(float hPixelWidth, float vPixelWidth){
int store_colour, seedrowColour, bytePointer, seedrowStart, seedrowEnd;
int byteOffset, bitOffset, xByte;
unsigned char xd;
// Copy all seed data across to new row
store_colour = printColour;
xpos = marginleftp;
for (seedrowColour = 0; seedrowColour < colourSupport; seedrowColour++) {
printColour = seedrowColour;
switch (seedrowColour) {
case 3:
printColour = 4; // Yellow
break;
case 4:
printColour = 9; // Light Magenta
break;
case 5:
printColour = 10; // Light Cyan
break;
}
seedrowStart = (seedrowColour * pageSetWidth) /8;
seedrowEnd = seedrowStart + (pageSetWidth / 8);
bytePointer = seedrowStart + (xpos / 8);
bitOffset = 7 - ((int) xpos & 7); // Bit & 7 is cheaper than remainder % 8
for (byteOffset = bytePointer; byteOffset < seedrowEnd; byteOffset++) {
xd = seedrow[byteOffset];
if (xd > 0) {
for (xByte = bitOffset; xByte >= 0; xByte--) {
if (isNthBitSet(xd,xByte)) {
putpixelbig(xpos, ypos, hPixelWidth, vPixelWidth);
}
xpos += hPixelWidth;
}
} else {
xpos += hPixelWidth * (bitOffset + 1);
}
bitOffset=7;
}
xpos = marginleftp;
}
printColour = store_colour;
}
void _print_incomingDataByte(int compressMode, unsigned char xd, int seedrowStart, int seedrowEnd, float hPixelWidth, float vPixelWidth) {
int byteOffset, bitOffset, xByte;