-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.cpp
2024 lines (1953 loc) · 154 KB
/
main.cpp
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
//
// This Conversion program was written by Marmayogi, Astrologer and Palmist, Sri Mahakali Jyothida Nilayam, Coimbatore, India.
// This Converts TTF to a Type 2 CIDFont, with base font Type 42, which can be accessed through a postscript program.
// This is particulary useful for Indian Languages having glyphs in excess of 256 in the character set.
//
// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include "ttf.h"
static const char* asTablesRequired[] = {
"cmap", // character to glyph mapping
"glyf", // glyph data
"head", // font header
"hhea", // horizontal header
"hmtx", // horizontal metrics
"loca", // index to location
"maxp", // maximum profile
"name", // naming
"post", // PostScript
"prep", // control value program
};
typedef struct STTFCmapTable_GRecord { // Each sequential map group record specifies a character range and the starting glyph ID mapped from the first character.
uint16_t startCharCode; // First character code in this group.
uint16_t endCharCode; // Last character code in this group.
uint16_t startGlyphID; // Glyph index corresponding to the starting character code. subsequent charcters are mapped to sequential glyphs
} STTFCmapTable_GRecord;
const char cSP = ' ';
void psInitPostscript(FILE *fps, const char* pIndianFontName)
{
static const char *arrPS[] = {
"%!PS-Adobe-3.0",
"%%Pages: (atend)",
"%%LanguageLevel: 3",
"%%Creator: Marmayogi, Astrologer and Palmist, Sri Mahakali Jothida Nilayam, Coimbatore, India.",
"%%Title: (TTF2PostscriptCID Conversion Software)",
"%%DocumentPaperSizes: a4",
"%%Orientation: Portrait",
"%%DocumentMedia: Plain 595 842 80 white ()",
"%%EndComments",
"%%BeginDefaults",
"%%PageMedia: Plain",
"%%PageOrder: Ascend",
"%%PageOrientation: Portrait",
"%%EndDefaults",
"%----------------------------------------------------------",
"%%BeginProlog",
"%%EndProlog",
"%----------------------------------------------------------",
"%%Page: Marmayogi 1",
"newpath",
"%----------------------------------------------------------",
"/myHelvetica {/Helvetica findfont exch scalefont setfont} bind def", // 15 myHelvetica # Helvetica is data font
"/myTimesRoman {/Times-Roman findfont exch scalefont setfont} bind def", // 15 myTimesRoman # Times-Roman is data font
"/myTimesBold {/Times-Bold findfont exch scalefont setfont} bind def", // 15 myTimesBold # Times-Bold is data font
"%----------------------------------------------------------",
"/CTXT {dup stringwidth pop 3 -1 roll 2 copy lt {sub neg 2 div 4 -1 roll add 3 -1 roll} {pop pop 3 1 roll} ifelse moveto show} bind def", // Center text. usage: X Y Width (Text) CTX. For example: 36 300 500 (Marmayogi) CTXT
};
const short totalElements = sizeof(arrPS) / sizeof(char*);
short ii = -1;
while (++ii < totalElements) {
fprintf(fps, "%s\n", arrPS[ii]);
};
fprintf(fps, "/myfont {/%s findfont exch scalefont setfont} bind def\n", pIndianFontName);
}
void psPageNumber(FILE* fps, const int pPageNumber)
{
const int cPgNum_x = 530; // Page number which should be written at the bootm right side. (x-coordinate)
const int cPgNum_y = 5; // Page number which should be written at the bootm right side. (y-coordinate)
fprintf(fps, "gsave\n");
fprintf(fps, "11 myTimesRoman\n");
fprintf(fps, "%d %d moveto (Page) show\n", cPgNum_x, cPgNum_y); // Page title
fprintf(fps, "11 myTimesBold\n");
fprintf(fps, "6 0 rmoveto (%d) show\n", pPageNumber); // page number (starts from one)
fprintf(fps, "grestore\n");
}
void psWriteFooter(FILE* fps)
{
static const char* psLogo = "This conversion software was designed, developed and distributed by Marmayogi, Sri Mahakali Jothida Nilayam, Coimbatore, India.";
const short cFooterLogo_x = 36; // footer logo x co-ordinate
const short cFooterLogo_y = 5; // footer logo y co-ordinate
const short cFooterLine_x = 36; // footer line x co-ordinate
const short cFooterLine_y = 15; // footer line y co-ordinate
const short cLineLength = 500; // line length in points
// set footer
fprintf(fps, "gsave\n");
fprintf(fps, "newpath\n");
fprintf(fps, "9 myTimesRoman %d %d %d (%s) CTXT\n", cFooterLogo_x, cFooterLogo_y, cLineLength, psLogo); // write logo at footer
fprintf(fps, "0.5 setgray %d %d moveto 36 %d add 0 rlineto stroke\n", cFooterLine_x, cFooterLine_y, cLineLength); // write footer line hanging over logo
fprintf(fps, "grestore\n");
}
void psSendPageToDevice(FILE* fps)
{
fprintf(fps, "showpage\n"); // print page to postscript device
}
void psFlushReport(FILE* fps, const short pPageNum)
{
psWriteFooter(fps);
psPageNumber(fps, pPageNum); // write page number
psSendPageToDevice(fps); // print page to postscript device}
}
void psInitNextPage(FILE* fps, const int pPageOrdinal)
{
fprintf(fps, "%sPage: Marmayogi %4d\n", "%%", pPageOrdinal); // page number is made up of a label and an ordinal number
}
int cmpfuncGroupRecordFormat12(const void* a, const void* b)
{
const STTFCmapTable_SequentialMapGroup_Record* first = static_cast<const STTFCmapTable_SequentialMapGroup_Record*>(a);
const STTFCmapTable_SequentialMapGroup_Record* second = static_cast<const STTFCmapTable_SequentialMapGroup_Record*>(b);
if (first->startGlyphID == second->startGlyphID) return 0;
else if (first->startGlyphID < second->startGlyphID) return -1;
else return 1;
}
int cmpfuncGroupRecordFormat4(const void* a, const void* b)
{
const STTFCmapTable_GRecord* first = static_cast<const STTFCmapTable_GRecord*>(a);
const STTFCmapTable_GRecord* second = static_cast<const STTFCmapTable_GRecord*>(b);
if (first->startGlyphID == second->startGlyphID) return 0;
else if (first->startGlyphID < second->startGlyphID) return -1;
else return 1;
}
void printAlphabet_T42(FILE* fps, const STTFCmapTable_SequentialMapGroup_Record* pGroupRecord, const short pTotalGroupRecords, const short pTotalGlyphs, const char* pIndianFontName)
{
//
// This function displays glyphs with cid and unicode points for format 12.
// Print Alphabets in 8 X 16 matrix form.
//
// 1. fps is input parameter of type FILE which holds Postscript program instructions.
// 2. pGroupRecord is input array of type STTFCmapTable_SequentialMapGroup_Record supplying start and ending unicode along with start glyph identifier.
// 3. pTotalGroupRecords is input parameter indicating total group records.
// 4. pTotalGlyphs is input parameter indicating total glyphs associated with the font.
// 5. pIndianFontName is input parameter which is the font name of t42 cid font file.
//
STTFCmapTable_SequentialMapGroup_Record* grec = NULL;
grec = new STTFCmapTable_SequentialMapGroup_Record[pTotalGroupRecords];
if (!grec) {
fprintf(stderr, " printAlphabet_T42(): Memory Allocation error of Cmap. SequentialMapGroup_Record: %d.\n", pTotalGroupRecords); // error
fprintf(stderr, "\nHit any key to exit.......\n"); getchar(); exit(1);
}
const size_t size = sizeof(STTFCmapTable_SequentialMapGroup_Record) * pTotalGroupRecords; // size of total records
memcpy_s(static_cast<void*>(grec), size, static_cast<const void*>(pGroupRecord), size); // transfer records.
qsort(grec, static_cast<size_t>(pTotalGroupRecords), sizeof(STTFCmapTable_SequentialMapGroup_Record), cmpfuncGroupRecordFormat12); // sort group records based on startGlyphID.
psInitPostscript(fps, pIndianFontName); // Initialize Postscript.
const char* pFontName = "myfont"; // Font to print Glyphs.
const char* pTitleFontName = "myHelvetica"; // Font to print Titles
int pagenum = 0; // Initialize page numbers.
const short lcResidual = pTotalGlyphs % 128; // Glyphs available in the final page.
const short lcLoop = pTotalGlyphs / 128 + (lcResidual > 0); // Total number pages which will accommodate all the glyphs.
uint32_t unicodePoint; // unicode correponding to Glyph
int32_t idxGrp = -1; // index whose range is from 0 to pTotalGroupRecords-1.
uint32_t range = 0; // Number of glyphs having contiguous unicode points.
uint32_t startGlyphID; // startGlyphID corresponding to GlyphID indexed by idxGrp.
for (short ii = 0; ii < lcLoop; ii++) {// Total Pages
for (short jj = 0, cntGlyphPerPage = 0; jj < 8; jj++) {
unsigned int titlecode = ii * 128 + (jj << 4);
fprintf(fps, "13 %s\n", pTitleFontName); // set font to print table title
fprintf(fps, "50 775 530 (Glyph) CTXT\n"); // Write title 'Glyph' by centering at paper.
fprintf(fps, "10 %s\n", pTitleFontName); // set font to print table title
fprintf(fps, "50 %d add 760 moveto (%d) show\n", 68 * jj, titlecode); // print column title
fprintf(fps, "50 750 moveto %d 0 rlineto stroke\n", 530); // Horizontal line
fprintf(fps, "35 735 moveto 0 -%d rlineto stroke\n", 660); // Vertical line
for (short kk = 0; kk < 16; kk++) {
if (lcResidual && ii == lcLoop - 1 && cntGlyphPerPage == lcResidual) goto Label_Getout; // All glyphs are printed so getout.
uint16_t cid = ii * 128 + jj * 16 + kk; // CID value corresponding to the Glyph. Range is between 0 and pTotalGlyphs-1.
const short xPos = 68 * jj; // X-Coordinate.
const short yPos = 43 * kk; // Y-Coordinate.
fprintf(fps, "10 %s\n", pTitleFontName); // set font to print row title
fprintf(fps, "20 725 %d sub moveto (%1X) show\n", yPos, kk); // print row title.
fprintf(fps, "12 %s\n", pFontName); // set font to print alphabets.
fprintf(fps, "50 %d add 725 %d sub moveto <%04x> show\n", xPos, yPos, cid); // print alphabet
fprintf(fps, "9 %s\n", pTitleFontName); // set font to print character code.
fprintf(fps, "50 %d add 725 %d sub moveto (%d) show\n", xPos, yPos+15, cid); // print cid decimal value
if (!ii && !jj && !kk) {// print .notdef glyph
fprintf(fps, "50 %d add 725 %d sub moveto (none) show\n", xPos, yPos+25); // as .notdef glyph is not associated with any Unicode so print 'none'.
}
else {
if (range) {
++unicodePoint < 65536 ? fprintf(fps, "50 %d add 725 %d sub moveto (U+%04X) show\n", xPos, yPos + 25, unicodePoint) : // print unicode point in 4 hex digits.
fprintf(fps, "50 %d add 725 %d sub moveto (U+%06X) show\n", xPos, yPos + 25, unicodePoint); // print unicode point in 6 hex digits.
if (range) range--; // decrement range. There are still glyphs to printed that falls into contiguous range.
}
else {
++idxGrp;
startGlyphID = grec[idxGrp].startGlyphID; // Start Glyph Id
if (startGlyphID > cid) {
fprintf(fps, "50 %d add 725 %d sub moveto (none) show\n", xPos, yPos + 25); // as glyph is not associated with any Unicode so print 'none'.
--idxGrp; // Decrement until startGlyphID equals cid.
}
else {
range = grec[idxGrp].endCharCode - grec[idxGrp].startCharCode + 1; // Find out range of contiguous glyphs having Unicode Points.
unicodePoint = grec[idxGrp].startCharCode;
unicodePoint < 65536 ? fprintf(fps, "50 %d add 725 %d sub moveto (U+%04X) show\n", xPos, yPos + 25, unicodePoint) : // print unicode point in 4 hex digits.
fprintf(fps, "50 %d add 725 %d sub moveto (U+%06X) show\n", xPos, yPos + 25, unicodePoint); // print unicode point in 6 hex digits.
if (range) range--; // decrement range. There are still glyphs to printed that falls into contiguous range.
}
}
}
cntGlyphPerPage++;
}
}
Label_Getout:
psFlushReport(fps, ++pagenum);
if (ii < lcLoop - 1) {
psInitNextPage(fps, pagenum + 1); // setup for next page
}
}
delete[]grec; // release memeory allocated for 'cmap' format 12 SequentialMapGroup_Record
}
void printAlphabet_T42(FILE* fttf, FILE* fps, const long pOffsetIdRangeOffset, const STTFCmapTable_Format_4_Segment_Array pSegArray, const uint16_t pSegCount, const short pTotalGlyphs, uint16_t *pDerivedGroupRecords, const char* pIndianFontName)
{
//
// This function displays glyphs with cid and unicode points for format 4.
// Print Alphabets in 8 X 16 matrix form.
//
// 1. fttf is the input file handle for ttf font.
// 2. fps is the input file handle for postscript program.
// 3. pOffsetIdRangeOffset is an input parameter which is an offset to idRangeOffset for format 4 w.r.t. the beginning of file.
// 4. pSegArray is an unput structure containing four parallel arrays describing the segments (one segment for each contiguous range of codes)
// 5. pSegCount is an an input parameter indicating the size of each of four four parallel arrays.
// 6. pTotalGlyphs is an input parameter indicating total glyphs associated with the font.
// 7. pDerivedGroupRecords is an output parameter that passes out derived group records from segment count required to display CID and Unicode Point.
// 8. pIndianFontName is input parameter which is the font name of t42 cid font file.
//
uint16_t cntGrpRecords = 0;
for (uint16_t ii = 0; ii < pSegCount-1; ii++) {// pSegCount includes final entry 0xffff which should be discarded.
cntGrpRecords += (pSegArray.idRangeOffset[ii] ? pSegArray.endCode[ii] - pSegArray.startCode[ii] + 1 : 1);
}
STTFCmapTable_GRecord* grec = NULL;
grec = new STTFCmapTable_GRecord[cntGrpRecords];
if (!grec) {
fprintf(stderr, " printAlphabet_T42(): Memory Allocation error of Cmap. cntGrpRecords: %d.\n", cntGrpRecords); // error
fprintf(stderr, "\nHit any key to exit.......\n"); getchar(); exit(1);
}
uint16_t kk = 0; // Ranges between 0 and cntGrpRecords-1
for (uint16_t ii = 0; ii < pSegCount-1; ii++) {
if (!pSegArray.idRangeOffset[ii]) {
uint16_t glyphid = pSegArray.idDelta[ii] + pSegArray.startCode[ii]; // glyph index = pSegArray.idDelta[ii] + character code.
grec[kk].startGlyphID = glyphid; // store glyph index
grec[kk].startCharCode = pSegArray.startCode[ii]; // copy start code.
grec[kk].endCharCode = pSegArray.endCode[ii]; // copy end code.
//printf("zero......%3d) delta=%d start=%04x end=%04X glyphid=%u", ii, pSegArray.idDelta[ii], grec[kk].startCharCode, grec[kk].endCharCode, glyphid); getchar();
kk++;
}
else {
uint16_t loop = pSegArray.endCode[ii] - pSegArray.startCode[ii] + 1;
uint16_t jj = 0;
do {
uint16_t OffsetInBytes = ii * 2 + pSegArray.idRangeOffset[ii] + 2 * jj; // (pSegArray.startCode[ii + jj] - pSegArray.startCode[ii]);
long glyphIndexAddress = pOffsetIdRangeOffset + OffsetInBytes;
if (fseek(fttf, glyphIndexAddress, SEEK_SET)) {
fprintf(stderr, " printAlphabet_T42(): File seek error in 'cmap` table. glyphIndexAddress: %ld, Error(%d)\n", glyphIndexAddress, errno); // error
fprintf(stderr, "\nHit any key to exit.......\n"); getchar(); exit(1);
}
uint16_t glyphid;
fread(&glyphid, sizeof(uint16_t), 1, fttf);
if (errno) {
fprintf(stderr, " printAlphabet_T42(): File error while reading object glyphid. Error(%d)\n", errno); // error
fprintf(stderr, "\nHit any key to exit.......\n"); getchar(); exit(1);
}
glyphid = SWAPWORD(glyphid); // convert to little endian.
if (glyphid) glyphid += pSegArray.idDelta[ii]; // find out Glyph id.
grec[kk + jj].startGlyphID = glyphid; // store glyph id.
grec[kk + jj].startCharCode = pSegArray.startCode[ii]+jj; // start Character Code.
grec[kk + jj].endCharCode = pSegArray.startCode[ii] + jj; // end Character Code.
//printf("non-zero..%3d) OffsetInBytes=%u start=%04x end=%04X glyphid=%u", jj, OffsetInBytes, grec[kk+jj].startCharCode, grec[kk+jj].endCharCode, glyphid); getchar();
} while (++jj < loop);
kk += loop;
}
}
//printf("kk=%u cntGrpRecords=%u", kk, cntGrpRecords); getchar();
qsort(grec, static_cast<size_t>(cntGrpRecords), sizeof(STTFCmapTable_GRecord), cmpfuncGroupRecordFormat4); // sort group records based on startGlyphID.
//printf("after sort.....start=%04x end=%04X glyphid=%u", grec[0].startCharCode, grec[0].endCharCode, grec[0].startGlyphID); getchar();
//for (uint16_t ii = cntGrpRecords - 4; ii < cntGrpRecords; ii++) {printf("start[%u]=%04x end[%u]=%04X glyphid[%u]=%u", ii,grec[ii].startCharCode, ii,grec[ii].endCharCode, ii,grec[ii].startGlyphID); getchar();}
/**
FILE* ftmp;
fopen_s(&ftmp, "Grec.txt", "w"); fprintf(ftmp, "slno\t....start.....\t\t....end.....\t\tglyph id\n");
for (short ii = 0; ii < cntGrpRecords; ii++) { fprintf(ftmp, "%4d\t%5u\t%04X\t\t%5u\t%04x\t\t%u\n", ii, grec[ii].startCharCode, grec[ii].startCharCode, grec[ii].endCharCode, grec[ii].endCharCode, grec[ii].startGlyphID); }
fclose(ftmp);
*/
psInitPostscript(fps, pIndianFontName); // Initialize Postscript.
const char* pFontName = "myfont"; // Font to print Glyphs.
const char* pTitleFontName = "myHelvetica"; // Font to print Titles
int pagenum = 0; // Initialize page numbers.
const short lcResidual = pTotalGlyphs % 128; // Glyphs available in the final page.
const short lcLoop = pTotalGlyphs / 128 + (lcResidual > 0); // Total number pages which will accommodate all the glyphs.
uint32_t unicodePoint; // unicode correponding to Glyph
int32_t idxGrp = -1; // index whose range is from 0 to cntGrpRecords-1.
uint32_t range = 0; // Number of glyphs having contiguous unicode points.
uint32_t startGlyphID; // startGlyphID corresponding to GlyphID indexed by idxGrp.
for (short ii = 0; ii < lcLoop; ii++) {// Total Pages
for (short jj = 0, cntGlyphPerPage = 0; jj < 8; jj++) {
unsigned int titlecode = ii * 128 + (jj << 4);
fprintf(fps, "10 %s\n", pTitleFontName); // set font to print table title
fprintf(fps, "50 %d add 760 moveto (%d) show\n", 68 * jj, titlecode); // print column title
fprintf(fps, "50 750 moveto %d 0 rlineto stroke\n", 530); // Horizontal line
fprintf(fps, "35 735 moveto 0 -%d rlineto stroke\n", 660); // Vertical line
fprintf(fps, "13 %s\n", pTitleFontName); // set font to print table title
fprintf(fps, "50 790 530 (Glyph) CTXT\n"); // Write title 'Glyph' by centering at paper.
for (short kk = 0; kk < 16; kk++) {
if (lcResidual && ii == lcLoop - 1 && cntGlyphPerPage == lcResidual) goto Label_Getout; // All glyphs are printed so getout.
uint16_t cid = ii * 128 + jj * 16 + kk; // CID value corresponding to the Glyph. Range is between 0 and pTotalGlyphs-1.
const short xPos = 68 * jj; // X-Coordinate.
const short yPos = 43 * kk; // Y-Coordinate.
fprintf(fps, "10 %s\n", pTitleFontName); // set font to print row title
fprintf(fps, "20 725 %d sub moveto (%1X) show\n", yPos, kk); // print row title.
fprintf(fps, "12 %s\n", pFontName); // set font to print alphabets.
fprintf(fps, "50 %d add 725 %d sub moveto <%04x> show\n", xPos, yPos, cid); // print alphabet
fprintf(fps, "9 %s\n", pTitleFontName); // set font to print character code.
fprintf(fps, "50 %d add 725 %d sub moveto (%d) show\n", xPos, yPos+15, cid); // print cid decimal value
if (!ii && !jj && !kk) {// print .notdef glyph
fprintf(fps, "50 %d add 725 %d sub moveto (none) show\n", xPos, yPos+25); // as .notdef glyph is not associated with any Unicode so print 'none'.
}
else {
if (range) {
fprintf(fps, "50 %d add 725 %d sub moveto (U+%04X) show\n", xPos, yPos + 25, ++unicodePoint); // print unicode point in 4 hex digits.
//printf(".......%2d) range=%u idxGrp=%d unicodePoint=%04X", kk, range, idxGrp, unicodePoint); getchar();
if (range) range--; // decrement range. There are still glyphs to printed that falls into contiguous range.
}
else {
++idxGrp;
startGlyphID = grec[idxGrp].startGlyphID; // Start Glyph Id
//if (ii == lcLoop - 1 && idxGrp > cntGrpRecords - 14) { printf("above none....%2d/%d) idxGrp=%d cid=%d startGlyphID=%d start=%04X end=%04X", kk, jj, idxGrp, cid, startGlyphID, grec[idxGrp].startCharCode, grec[idxGrp].endCharCode); getchar(); }
if (idxGrp > cntGrpRecords-1 || startGlyphID > cid) {
fprintf(fps, "50 %d add 725 %d sub moveto (none) show\n", xPos, yPos + 25); // as glyph is not associated with any Unicode so print 'none'.
--idxGrp; // Decrement until startGlyphID equals cid.
}
else {
if (startGlyphID < cid) idxGrp++; // out of turn startGlyphID w.r.t. cid. This happened in Microsoft's Latha font. start(U+2219), end(U+2219) and startGlyphID(346). 1st/Nov/2022.
range = grec[idxGrp].endCharCode - grec[idxGrp].startCharCode + 1; // Find out range of contiguous glyphs having Unicode Points.
unicodePoint = grec[idxGrp].startCharCode;
//if (ii == lcLoop - 1 && idxGrp > cntGrpRecords - 14) { printf("..............%2d/%d) idxGrp=%d range=%d unicode=%04X cid=%d startGlyphID=%d start=%04X end=%04X", kk, jj, idxGrp, range, unicodePoint, cid, startGlyphID, grec[idxGrp].startCharCode, grec[idxGrp].endCharCode); getchar(); }
fprintf(fps, "50 %d add 725 %d sub moveto (U+%04X) show\n", xPos, yPos + 25, unicodePoint); // print unicode point in 4 hex digits.
//printf("else...%2d) range=%u idxGrp=%d unicodePoint=%04X", kk, range, idxGrp, unicodePoint); getchar();
if (range) range--; // decrement range. There are still glyphs to printed that falls into contiguous range.
}
}
}
cntGlyphPerPage++;
}
}
Label_Getout:
psFlushReport(fps, ++pagenum);
if (ii < lcLoop - 1) {
psInitNextPage(fps, pagenum + 1); // setup for next page
}
}
delete[]grec; // release memeory allocated for 'cmap' format 12 SequentialMapGroup_Record
if (pDerivedGroupRecords != NULL) *pDerivedGroupRecords = cntGrpRecords;
}
void printAlphabet_T42(FILE* fps, const short pTotalGlyphs, const char* pIndianFontName)
{
//
// This font has been convertedf from ttf to CIDFont type 2 with base font type 42 (double byte).
// Print Alphabets in 8 X 16 matrix form
//
// 1. fps is input parameter of type FILE which holds Postscript program instructions.
// 2. pTotalGlyphs is input parameter indicating total glyphs associated with the font.
// 3. pIndianFontName is input parameter which is the font name of t42 cid font file.
//
psInitPostscript(fps, pIndianFontName);
const char* pFontName = "myfont"; // Font to print Glyphs.
const char* pTitleFontName = "myHelvetica"; // Font to print Titles
int pagenum = 0;
const short lcResidual = pTotalGlyphs % 128;
const short lcLoop = pTotalGlyphs / 128 + (lcResidual > 0);
for (short ii = 0; ii < lcLoop; ii++) {
for (short jj = 0, cntGlyph = 0; jj < 8; jj++) {
unsigned int titlecode = ii * 128 + (jj << 4);
fprintf(fps, "10 %s\n", pTitleFontName); // set font to print table title
fprintf(fps, "50 %d add 760 moveto (%d) show\n", 35 * jj, titlecode); // print column title
fprintf(fps, "350 %d add 760 moveto (%d) show\n", 30 * jj, titlecode); // print column title
fprintf(fps, "50 750 moveto %d 0 rlineto stroke\n", 530); // Horizontal line
fprintf(fps, "35 735 moveto 0 -%d rlineto stroke\n", 615); // Vertical line
fprintf(fps, "13 %s\n", pTitleFontName); // set font to print table title
fprintf(fps, "50 790 260 (Glyph) CTXT\n"); // Write title 'Glyph' by centering at LHS.
fprintf(fps, "350 790 230 (CID) CTXT\n"); // Write title 'CID' by centering at RHS.
for (short kk = 0; kk < 16; kk++) {
if (lcResidual && ii == lcLoop - 1 && cntGlyph == lcResidual) goto Label_Getout;
uint16_t cid = ii * 128 + jj * 16 + kk; // CID value corresponding to the Glyph.
const short xPos_1 = 35 * jj; // X-Coordinate.
const short xPos_2 = 30 * jj; // X-Coordinate.
const short yPos = 40 * kk; // Y-Coordinate.
fprintf(fps, "10 %s\n", pTitleFontName); // set font to print row title
fprintf(fps, "20 725 %d sub moveto (%1X) show\n", yPos, kk); // print row title.
fprintf(fps, "12 %s\n", pFontName); // set font to print alphabets.
fprintf(fps, "50 %d add 725 %d sub moveto <%04x> show\n", xPos_1, yPos, cid); // print alphabets
fprintf(fps, "11 %s\n", pTitleFontName); // set font to print character code.
fprintf(fps, "350 %d add 725 %d sub moveto (%d) show\n", xPos_2, yPos, cid); // print character code of alphabets.
cntGlyph++;
}
}
Label_Getout:
psFlushReport(fps, ++pagenum);
if (ii < lcLoop - 1) {
psInitNextPage(fps, pagenum + 1); // setup for next page
}
}
}
void debugSwap()
{
//
// This functions tests macros defined in ttf.h
//
uint16_t val_16 = 0x6475;
fprintf(stdout, "Big Endian : 0x%04x\n", val_16);
fprintf(stdout, " High byte : 0x%02x\n", HIBYTE(val_16));
fprintf(stdout, " Low Byte : 0x%02x\n", LOBYTE(val_16));
fprintf(stdout, "Little Endian : 0x%04x\n\n", SWAPWORD(val_16));
uint32_t val_32 = 0x15251626;
fprintf(stdout, "Big Endian : 0x%08x\n", val_32);
fprintf(stdout, " High Word : 0x%02x\n", LOWORD(val_32));
fprintf(stdout, " Low Word : 0x%02x\n", HIWORD(val_32));
fprintf(stdout, "Little Endian : 0x%08x\n\n", SWAPLONG(val_32));
uint64_t val_64 = 0x3848394915251626; // 38 48 39 49 | 15 25 16 26
#if _MSC_VER // Visual Studio
fprintf(stdout, "Big Endian : 0x%016llx\n", val_64);
fprintf(stdout, " High DWord : 0x%08lx\n", HILONG(val_64));
fprintf(stdout, " Low DWord : 0x%08lx\n", LOLONG(val_64));
fprintf(stdout, "Little Endian : 0x%016llx\n\n", SWAPLONGLONG(val_64));
#elif __GNUC__ || __CYGWIN__ // gcc
fprintf(stdout, "Big Endian : 0x%016lx\n", val_64);
fprintf(stdout, " High DWord : 0x%08x\n", HILONG(val_64));
fprintf(stdout, " Low DWord : 0x%08x\n", LOLONG(val_64));
fprintf(stdout, "Little Endian : 0x%016lx\n\n", SWAPLONGLONG(val_64));
#endif
}
void printString(const char *pString)
{
//
// This functions printfs pString parameter which is Hexadecimal string representing Subtable and Directory for Table entries.
// Total bytes of this string will be sizeof(STTFOffsetSubTable) + sizeof(STTFTableDirectory) * NumberOfTables.
//
const char cSP = ' ';
unsigned int scalerType, numOfTables, searchRange, entrySelector, rangeShift;
#if _MSC_VER // Visual Studio c++ compiler.
int retvalue = sscanf_s(pString, "%8x", &scalerType);
retvalue = sscanf_s(pString+8, "%4x", &numOfTables); // total 1 fields
retvalue = sscanf_s(pString+12, "%4x", &searchRange);
retvalue = sscanf_s(pString+16, "%4x", &entrySelector);
retvalue = sscanf_s(pString+20, "%4x", &rangeShift);
#elif __GNUC__ // gcc compiler.
sscanf(pString, "%8x", &scalerType);
sscanf(pString+8, "%4x", &numOfTables); // total 1 fields
sscanf(pString+12, "%4x", &searchRange);
sscanf(pString+16, "%4x", &entrySelector);
sscanf(pString+20, "%4x", &rangeShift);
#endif
fprintf(stdout, "\n ScalarType NumOfTables SearchRange EntrySelector RangeShift\n");
fprintf(stdout, " %u(0x%08X) %*c%u(0x%04X) %*c%u(0x%04X) %*c%u(0x%04X) %*c%u(0x%04X)\n\n",
scalerType, scalerType,
5, cSP, numOfTables, numOfTables,
5, cSP, searchRange, searchRange,
5, cSP, entrySelector, entrySelector,
7, cSP, rangeShift, rangeShift
);
fprintf(stdout, " Table Checksum Offset Length\n");
fprintf(stdout, " ---------------------------------------------------------------------------------\n");
for (uint16_t ii = 0, addr=24; ii < numOfTables; ii++, addr += 32) {
char tag[4] = {' '};
unsigned int checksum, offset, length;
#if _MSC_VER // Visual Studio c++ compiler.
for (short jj = 0; jj < 4; jj++) {
unsigned int byte;
int retvalue = sscanf_s(pString+addr+jj*2, "%2x", &byte); // extract table name
tag[jj] = byte & 0xff;
}
retvalue = sscanf_s(pString+addr+8, "%8x", &checksum); // extract checksum
retvalue = sscanf_s(pString+addr+16, "%8x", &offset); // extract offset
retvalue = sscanf_s(pString+addr+24, "%8x", &length); // extract length
#elif __GNUC__ // gcc compiler.
for (short jj = 0; jj < 4; jj++) {
unsigned int byte;
sscanf(pString+addr+jj*2, "%2x", &byte); // extract table name
tag[jj] = byte & 0xff;
}
sscanf(pString+addr+8, "%8x", &checksum); // extract checksum
sscanf(pString+addr+16, "%8x", &offset); // extract offset
sscanf(pString+addr+24, "%8x", &length); // extract length
#endif
char bufCheckSum[50], bufOffset[50], bufLength[50];
sprintf_s(bufCheckSum, sizeof(bufCheckSum), "%u(0x%08X)", checksum, checksum);
sprintf_s(bufOffset, sizeof(bufOffset), "%u(0x%08X)", offset, offset);
sprintf_s(bufLength, sizeof(bufLength), "%u(0x%08X)", length, length);
fprintf(stdout, " %2d) %.*s %*c%-25s %*c%-17s %*c%-17s\n",
ii + 1,
4, tag,
5, cSP, bufCheckSum,
5, cSP, bufOffset,
5, cSP, bufLength
);
}
getchar();
}
void debugString()
{
const char* string[] = {
"000100000008008000030000636D617001B8B66D0000008C0000131C676C79667DF9A7780000"
"13A80000BEF46865616418F1DCC20000D29C000000366868656109AB08690000D2D400000024"
"686D74788ABE40E10000D2F8000008546C6F63610337D3CD0000DB4C0000042E6D6178700227"
"018C0000DF7C000000207072657068068C850000DF9C0000000700",
"000100000008008000030000636D617001B8B66D0000008C0000131C676C79665E1E87780000"
"13A80000BEF46865616418F1DCC20000D29C000000366868656109AB08690000D2D400000024"
"686D74788ABE40E10000D2F8000008546C6F63610337D3CD0000DB4C0000042E6D6178700227"
"018C0000DF7C000000207072657068068C850000DF9C0000000700",
"00010000000A008000030020636D617001B8B66D000000AC0000131C676C79665E1E87780000"
"13C80000BEF46865616418F1DCC20000D2BC000000366868656109AB08690000D2F400000024"
"686D74788ABE40E10000D318000008546C6F63610337D3CD0000DB6C0000042E6D6178700227"
"018C0000DF9C000000206E616D65970DBC3F0000DFBC0000056E706F737427E56ADE0000E52C"
"0000157F7072657068068C850000FAAC0000000700",
};
for (short ii = 0; ii < 3; ii++) {
printString(string[ii]);
}
}
void debugSubTables(const STTFOffsetSubTable pSubTable, const char* pTrueTypeFontFile)
{
const char* ptrLine = " ------------------------------------------------------------------------------";
fprintf(stdout, "\n Debug(SubTables)................................................................\n");
fprintf(stdout, " True Type Font File : %s\n", pTrueTypeFontFile);
fprintf(stdout, " Scalar Type : %u(0x%08X)\n", pSubTable.scalerType, pSubTable.scalerType);
fprintf(stdout, " Number of Tables : %u(0x%04X)\n", pSubTable.numOfTables, pSubTable.numOfTables);
fprintf(stdout, " Search Range : %u(0x%04X)\n", pSubTable.searchRange, pSubTable.searchRange);
fprintf(stdout, " Entry Selector : %u(0x%04X)\n", pSubTable.entrySelector, pSubTable.entrySelector);
fprintf(stdout, " Range Shift : %u(0x%04X)\n", pSubTable.rangeShift, pSubTable.rangeShift);
fprintf(stdout, "%s\n", ptrLine);
fprintf(stdout, "\nHit any key to continue.....\n"); getchar();
}
void debugListOfTables(const STTFTableDirectory* pListOfTables, const short pTotalTables, const short pTotalGlyps, const char* pPostScriptFontName, const char* pTrueTypeFontFile)
{
const char* ptrLine = " --------------------------------------------------------";
fprintf(stdout, "\n Debug(Directory of Tables)......................................................\n");
fprintf(stdout, " True Type Font File : %s\n", pTrueTypeFontFile);
fprintf(stdout, " Postscript Font Name : %s\n", pPostScriptFontName);
fprintf(stdout, " Total Number of Tables : %d\n", pTotalTables);
fprintf(stdout, " Total Number of Glyps : %d\n", pTotalGlyps);
fprintf(stdout, "%s\n", ptrLine);
fprintf(stdout, " Table Checksum Offset Length\n");
fprintf(stdout, "%s\n", ptrLine);
short ii = 0;
do {
fprintf(stdout, " %2d) %.*s %*c%12u %*c%12u %*c%12u\n",
ii + 1,
4, pListOfTables[ii].tag, // The tables have names known as tags. Tags have the type uint32. Currently defined tag names consist of four characters. Tag names with less than four characters have trailing spaces.
4, cSP, pListOfTables[ii].checksum, // Check sum
4, cSP, pListOfTables[ii].offset, // Offset from beginning of file
4, cSP, pListOfTables[ii].length // length of the table in bytes
);
} while (++ii < pTotalTables);
fprintf(stdout, "%s\n", ptrLine);
fprintf(stdout, "\nHit any key to continue.....\n"); getchar();
}
void debugListOfNameRecords(const STTFNameRecord* pListOfNameRecords, char **pNameList, const short pTotalNameRecords, const char* pTrueTypeFontFile)
{
static const char* asPlatform[] = {
"Unicode", "Macintosh", "Reserved", "Microsoft"
};
/**
static const char* asPlatformSpecific_Macintosh[] = { // total 33
"Roman", "Japanese", "Chinese(Traditional)", "Korean", "Arabic", "Hebrew", "Greek", "Russian", "RSymbol",
"Devanagari", "Gurmukhi", "Gujarati", "Oriya", "Bengali", "Tamil", "Telugu", "Kannada", "Malayalam",
"Sinhalese", "Burmese", "Khmer", "Thai", "Laotian", "Georgian", "Armenian", "Chinese(Simplified)", "Tibetan",
"Mongolian", "Geez", "Slavic", "Vietnamese", "Sindhi", "(Uninterpreted)",
};
*/
static const char* asPlatformSpecific_Unicode[] = {
"Version 1.0", // Version 1.0 Semantics
"Version 1.1", // Version 1.1 Semantics
"ISO-10646", // ISO-10646 1993 Semantics
"Unicode", // Unicode semantics(BMP only)
"Unicode" // Unicode semantics(non-BMP allowed)
"Unicode Variation" // Unicode Variation Sequences
"Last Resort" // Last Resort
};
static const char* asNameString[] = { // total 25
"Copyright", "Family", "Style", "Unique", "Font", "Version", "PostScript", "Trade Mark", "Manufacturer",
"Designer", "Description", "Vendor URL", "Designer URL", "License", "License URL", "Reserved", "Preferred Family.", "Preferred Subfamily",
"Compatible ", "Sample text", "PostScript", "WWS family", "WWS subfamily", "Light", "Dark", "Variations",
};
const char* ptrLine = " --------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
fprintf(stdout, "\n Debug(NameRecords).........................................................................\n");
fprintf(stdout, " True Type Font File : %s\n", pTrueTypeFontFile);
fprintf(stdout, " Total Number of Name Records : %d\n", pTotalNameRecords);
fprintf(stdout, "%s\n", ptrLine);
fprintf(stdout, " Platform Platform Specific Language Name Length Offset Name\n");
fprintf(stdout, " Identifier Identifier Identifier Identifier (bytes) (bytes) String\n");
fprintf(stdout, "%s\n", ptrLine);
short ii = 0;
do {
//printf("%2d) platformID=%d specific=%d", ii+1, pListOfNameRecords[ii].platformID, pListOfNameRecords[ii].platformSpecificID); getchar();
char bufPlatform[20], bufPlatformSpecific[20], bufName[30];
sprintf_s(bufPlatform, sizeof(bufPlatform), "%1u (%s)", pListOfNameRecords[ii].platformID, asPlatform[pListOfNameRecords[ii].platformID]);
sprintf_s(bufPlatformSpecific, sizeof(bufPlatformSpecific), "%1u (%s)", pListOfNameRecords[ii].platformSpecificID, asPlatformSpecific_Unicode[pListOfNameRecords[ii].platformSpecificID]);
const char* sName = (pListOfNameRecords[ii].nameID <= 25) ? asNameString[pListOfNameRecords[ii].nameID] : pListOfNameRecords[ii].nameID >= 256 ? "Variations" :"Reserved";
sprintf_s(bufName, sizeof(bufName), "%3u (%s)", pListOfNameRecords[ii].nameID, sName);
fprintf(stdout, " %2d) %-14s %*c%-15s %*c%5u %*c%-25s %*c%5u %*c%5u %*c%.*s\n",
ii + 1,
bufPlatform, // Platform identifier code.
2, cSP, bufPlatformSpecific, // Platform-specific encoding identifier.
10, cSP, pListOfNameRecords[ii].languageID, // Language identifier.
3, cSP, bufName, // Name identifier.
6, cSP, pListOfNameRecords[ii].length, // Name string length in bytes.
4, cSP, pListOfNameRecords[ii].offset, // Name string offset in bytes from stringOffset.
4, cSP, 110, pNameList[ii] // Name string offset in bytes from stringOffset.
);
} while (++ii < pTotalNameRecords);
fprintf(stdout, "%s\n", ptrLine);
fprintf(stdout, "\nHit any key to continue.....\n"); getchar();
}
void debugListOfCMapEncodingRecords(const STTFCmapTable_Encoding* pListOfCmapEncodingRecords, const short pTotalEncodingRecords, const char* pTrueTypeFontFile)
{
static const char* asPlatform[] = {
"Unicode", "Macintosh", "Reserved", "Microsoft"
};
// BMP characters have these characteristics: Their code point values are between 0 and 65535 (or U+0000 and U+FFFF ).
// They can be encoded in a variable-length encoding using 8, 16, or 24 bits (1 to 3 bytes).
// They can be encoded in a fixed-length encoding using 16 bits (2 bytes).
static const char* asPlatformSpecific[4][33] = {
{// Unicode
"Version 1.0", // Version 1.0 Semantics
"Version 1.1", // Version 1.1 Semantics
"ISO-10646", // ISO-10646 1993 Semantics
"Unicode BMP-only", // Unicode semantics(BMP only). BMP=Basic Multilingual Plane
"Unicode non-BMP allowed", // Unicode semantics(non-BMP allowed)
"Unicode Variation", // Unicode Variation Sequences
"Last Resort", // Last Resort
},
{// Macintosh
"Roman", "Japanese", "Chinese(Traditional)", "Korean", "Arabic", "Hebrew", "Greek", "Russian", "RSymbol",
"Devanagari", "Gurmukhi", "Gujarati", "Oriya", "Bengali", "Tamil", "Telugu", "Kannada", "Malayalam",
"Sinhalese", "Burmese", "Khmer", "Thai", "Laotian", "Georgian", "Armenian", "Chinese(Simplified)", "Tibetan",
"Mongolian", "Geez", "Slavic", "Vietnamese", "Sindhi", "(Uninterpreted)",
},
{// Reserved
"",
},
{// Microsoft
"Symbol", // A format 4 subtable would be used, typically with up to 224 graphic characters assigned at code positions beginning with 0xF020.
"Unicode BMP-only", // Fonts that support only Unicode BMP characters (U+0000 to U+FFFF) on the Windows platform must use encoding 1 with a format 4 subtable.
"Shift-JIS",
"Shift-PRC",
"BigFive",
"Johab",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Unicode UCS-4" // Fonts that support Unicode supplementary-plane characters (U+10000 to U+10FFFF) with Format 12 subtable.", // Unicode full repertoire
},
};
static const char* asRemarks[4][11] = { //
{// Unicode platform (platform ID = 0)
"deprecated",
"deprecated",
"deprecated",
"Encoding ID 3 should be used in conjunction with 'cmap' subtable formats 4 or 6.",
"Encoding ID 4 should be used in conjunction with 'cmap' subtable formats 10 or 12.",
"Encoding ID 5 should use 'cmap' subtable format 14.",
"Encoding ID 6 should use 'cmap' subtable format 13.",
},
{// Macintosh platform (platform ID = 1)
"",
},
{// Deprecated
"",
},
{// Microsoft platform (platform ID = 3)
"Symbol (beginning with U+F020 typically with up to 224 graphic characters)", // A format 4 subtable would be used, typically with up to 224 graphic characters assigned at code positions beginning with 0xF020.
"Unicode BMP-only (UCS-2) characters (U+0000 to U+FFFF) with Format 4 subtable.", // Fonts that support only Unicode BMP characters (U+0000 to U+FFFF) on the Windows platform must use encoding 1 with a format 4 subtable.
"Shift-JIS",
"Shift-PRC",
"BigFive",
"Johab",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Unicode UCS-4. Fonts that support Unicode supplementary-plane characters (U+10000 to U+10FFFF) with Format 12 subtable.", // Unicode full repertoire
}
};
const char* ptrLine = " -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
fprintf(stdout, "\n Debug(CMap Encoding Subtables).............................................................................................................................................................\n");
fprintf(stdout, " True Type Font File : %s\n", pTrueTypeFontFile);
fprintf(stdout, " Total Number of Cmap Encoding Subtables : %d\n", pTotalEncodingRecords);
fprintf(stdout, "%s\n", ptrLine);
fprintf(stdout, " Platform Platform Specific Offset\n");
fprintf(stdout, " Identifier Encoding Identifier (bytes) Remarks\n");
fprintf(stdout, "%s\n", ptrLine);
short ii = 0;
do {
const uint16_t pid = pListOfCmapEncodingRecords[ii].platformID; // Platform ID
const uint16_t psid = pListOfCmapEncodingRecords[ii].platformSpecificID; // platform Specific ID
//printf("%2d) platformID=%d specific=%d", ii+1, pListOfNameRecords[ii].platformID, pListOfNameRecords[ii].platformSpecificID); getchar();
char bufPlatform[20], bufPlatformSpecific[50];
sprintf_s(bufPlatform, sizeof(bufPlatform), "%1u (%s)", pid, asPlatform[pid]);
sprintf_s(bufPlatformSpecific, sizeof(bufPlatformSpecific), "%2u (%s)", psid, asPlatformSpecific[pid][psid]);
fprintf(stdout, " %2d) %-14s %*c%-28s %*c%5u %*c%s\n",
ii + 1,
bufPlatform, // Platform identifier code.
2, cSP, bufPlatformSpecific, // Platform-specific encoding identifier.
7, cSP, pListOfCmapEncodingRecords[ii].offset, // Byte offset from beginning of table to the subtable for this encoding.
3, cSP, asRemarks[pid][psid] // Byte offset from beginning of table to the subtable for this encoding.
);
} while (++ii < pTotalEncodingRecords);
fprintf(stdout, "%s\n", ptrLine);
fprintf(stdout, "\nHit any key to continue.....\n"); getchar();
}
void debugCMapSegmeentArrayFormat_4(const STTFCmapTable_Format_4 pCmapFormat, const STTFCmapTable_Format_4_Segment_Array pSegArray, const uint16_t pSegmentCount, const uint16_t pDerivedGroupRecords, const uint16_t pPlatformID, const uint16_t pPlatformSpecificID, const char* pTrueTypeFontFile)
{
static const char* asPlatform[] = {
"Unicode", "Macintosh", "Reserved", "Microsoft"
};
// BMP characters have these characteristics: Their code point values are between 0 and 65535 (or U+0000 and U+FFFF ).
// They can be encoded in a variable-length encoding using 8, 16, or 24 bits (1 to 3 bytes).
// They can be encoded in a fixed-length encoding using 16 bits (2 bytes).
static const char* asPlatformSpecific[4][33] = {
{// Unicode
"Version 1.0 semantics", // Version 1.0 Semantics
"Version 1.1 semantics", // Version 1.1 Semantics
"ISO 10646 1993 semantics (deprecated)", // ISO-10646 1993 Semantics
"Unicode 2.0 or later semantics (BMP only)", // Unicode semantics(BMP only). BMP=Basic Multilingual Plane
"Unicode 2.0 or later semantics (non-BMP characters allowed)", // Unicode semantics(non-BMP allowed)
"Unicode Variation Sequences", // Unicode Variation Sequences
"Last Resort", // Last Resort
},
{// Macintosh
"Roman", "Japanese", "Chinese(Traditional)", "Korean", "Arabic", "Hebrew", "Greek", "Russian", "RSymbol",
"Devanagari", "Gurmukhi", "Gujarati", "Oriya", "Bengali", "Tamil", "Telugu", "Kannada", "Malayalam",
"Sinhalese", "Burmese", "Khmer", "Thai", "Laotian", "Georgian", "Armenian", "Chinese(Simplified)", "Tibetan",
"Mongolian", "Geez", "Slavic", "Vietnamese", "Sindhi", "(Uninterpreted)",
},
{// Reserved
"",
},
{// Microsoft
"Symbol", // A format 4 subtable would be used, typically with up to 224 graphic characters assigned at code positions beginning with 0xF020.
"Unicode BMP-only (UCS-2)", // Fonts that support only Unicode BMP characters (U+0000 to U+FFFF) on the Windows platform must use encoding 1 with a format 4 subtable.
"Shift-JIS",
"Shift-PRC",
"BigFive",
"Johab",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Unicode UCS-4" // Fonts that support Unicode supplementary-plane characters (U+10000 to U+10FFFF) with Format 12 subtable.", // Unicode full repertoire
},
};
const char* ptrLine_1 = " -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
const char* ptrLine_2 = " ----------------------------------------------------------------------------------- -----------------------------------------------------------------------------------";
fprintf(stdout, "\n Debug(CMap Format 4)....................................................................................................................................................................................\n");
fprintf(stdout, " True Type Font File : %s\n", pTrueTypeFontFile);
fprintf(stdout, " Platform Identifier : %u (%s)\n", pPlatformID, asPlatform[pPlatformID]);
fprintf(stdout, " Platform Specific Identifier : %u (%s)\n", pPlatformSpecificID, asPlatformSpecific[pPlatformID][pPlatformSpecificID]);
fprintf(stdout, " Format : %u\n", pCmapFormat.format); // Subtable format; set to 4.
fprintf(stdout, " Length of the subtable : %u bytes\n", pCmapFormat.length); // This is the length in bytes of the subtable.
if (pDerivedGroupRecords) {
fprintf(stdout, " Derived Group records from SegArray & SegCount : %d\n", pDerivedGroupRecords); // Derived group records from segment count required to display CID and Unicode Point.
}
fprintf(stdout, " segCountX2 (2 * segCount) : %u\n", pCmapFormat.segCountX2); // 2 × segCount.
fprintf(stdout, " searchRange (2 * ((2**floor(log2(segCount)))) : %u\n", pCmapFormat.searchRange); // Maximum power of 2 less than or equal to segCount, times 2. i.e. ((2**floor(log2(segCount))) * 2, where ** is an exponentiation operator)
fprintf(stdout, " entrySelector (floor(log2(segCount))) : %u\n", pCmapFormat.entrySelector); // Log2 of the maximum power of 2 less than or equal to numTables (log2(searchRange/2), which is equal to floor(log2(segCount)))
fprintf(stdout, " rangeShift ((segCount * 2) - searchRange) : %u\n", pCmapFormat.entrySelector); // segCount times 2, minus searchRange ((segCount * 2) - searchRange)
fprintf(stdout, "%s\n", ptrLine_1);
fprintf(stdout, " ....Start Code.... .....End Code..... Identifier Identifier ....Start Code.... .....End Code..... Identifier Identifier\n");
fprintf(stdout, " Decimal Unicode Decimal Unicode Delta RangeOffset Decimal Unicode Decimal Unicode Delta RangeOffset\n");
fprintf(stdout, "%s\n", ptrLine_2);
const uint16_t segmentLHS = pSegmentCount / 2 + (pSegmentCount % 2); // Segments at left hand side.
const uint16_t segmentRHS = pSegmentCount / 2; // Segments at right hand side.
for (uint16_t ii=0, jj=0; ii < segmentLHS; ii++, jj++) {
fprintf(stdout, " %3d) %-5u %*cU+%04X %*c%-5u %*cU+%04X %*c%5d %*c%5u",
ii + 1,
pSegArray.startCode[ii], // Starting character code for each segment.
6, cSP, pSegArray.startCode[ii], // Unicode Point.
10, cSP, pSegArray.endCode[ii], // Ending character code for each segment, last = 0xFFFF.
6, cSP, pSegArray.endCode[ii], // Unicode Point.
13, cSP, pSegArray.idDelta[ii], // Delta for all character codes in segment.
11, cSP, pSegArray.idRangeOffset[ii] // Offset in bytes to glyph indexArray, or 0.
);
if (jj < segmentRHS) {
uint16_t kk = segmentLHS + jj;
fprintf(stdout, "%*c %3d) %-5u %*cU+%04X %*c%-5u %*cU+%04X %*c%5d %*c%5u\n",
20, cSP,
kk + 1,
pSegArray.startCode[kk], // Starting character code for each segment.
6, cSP, pSegArray.startCode[kk], // Unicode Point.
10, cSP, pSegArray.endCode[kk], // Ending character code for each segment, last = 0xFFFF.
6, cSP, pSegArray.endCode[kk], // Unicode Point.
13, cSP, pSegArray.idDelta[kk], // Delta for all character codes in segment.
11, cSP, pSegArray.idRangeOffset[kk] // Offset in bytes to glyph indexArray, or 0.
);
}
else fprintf(stdout, "\n");
}
fprintf(stdout, "%s\n", ptrLine_1);
fprintf(stdout, "\nHit any key to continue.....\n"); getchar();
}
void debugCMapSegmeentArrayFormat_12(const STTFCmapTable_Format_12 pCmapFormat, const STTFCmapTable_SequentialMapGroup_Record *pGroupRecord, const uint16_t pPlatformID, const uint16_t pPlatformSpecificID, const char* pTrueTypeFontFile)
{
static const char* asPlatform[] = {
"Unicode", "Macintosh", "Reserved", "Microsoft"
};
// BMP characters have these characteristics: Their code point values are between 0 and 65535 (or U+0000 and U+FFFF ).
// They can be encoded in a variable-length encoding using 8, 16, or 24 bits (1 to 3 bytes).
// They can be encoded in a fixed-length encoding using 16 bits (2 bytes).
static const char* asPlatformSpecific[4][33] = {
{// Unicode
"Version 1.0 semantics", // Version 1.0 Semantics
"Version 1.1 semantics", // Version 1.1 Semantics
"ISO 10646 1993 semantics (deprecated)", // ISO-10646 1993 Semantics
"Unicode 2.0 or later semantics (BMP only)", // Unicode semantics(BMP only). BMP=Basic Multilingual Plane
"Unicode 2.0 or later semantics (non-BMP characters allowed)", // Unicode semantics(non-BMP allowed)
"Unicode Variation Sequences", // Unicode Variation Sequences
"Last Resort", // Last Resort
},
{// Macintosh
"Roman", "Japanese", "Chinese(Traditional)", "Korean", "Arabic", "Hebrew", "Greek", "Russian", "RSymbol",
"Devanagari", "Gurmukhi", "Gujarati", "Oriya", "Bengali", "Tamil", "Telugu", "Kannada", "Malayalam",
"Sinhalese", "Burmese", "Khmer", "Thai", "Laotian", "Georgian", "Armenian", "Chinese(Simplified)", "Tibetan",
"Mongolian", "Geez", "Slavic", "Vietnamese", "Sindhi", "(Uninterpreted)",
},
{// Reserved
"",
},
{// Microsoft
"Symbol", // A format 4 subtable would be used, typically with up to 224 graphic characters assigned at code positions beginning with 0xF020.
"Unicode BMP-only (UCS-2)", // Fonts that support only Unicode BMP characters (U+0000 to U+FFFF) on the Windows platform must use encoding 1 with a format 4 subtable.
"Shift-JIS",
"Shift-PRC",
"BigFive",
"Johab",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Unicode UCS-4" // Fonts that support Unicode supplementary-plane characters (U+10000 to U+10FFFF) with Format 12 subtable.", // Unicode full repertoire
},
};
const char* ptrLine_1 = " -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
const char* ptrLine_2 = " --------------------------------------------------------------- --------------------------------------------------------------- ---------------------------------------------------------------";
fprintf(stdout, "\n Debug(CMap Format 12).................................................................................................................................................................................................................\n");
fprintf(stdout, " True Type Font File : %s\n", pTrueTypeFontFile);
fprintf(stdout, " Platform Identifier : %u (%s)\n", pPlatformID, asPlatform[pPlatformID]);
fprintf(stdout, " Platform Specific Identifier : %u (%s)\n", pPlatformSpecificID, asPlatformSpecific[pPlatformID][pPlatformSpecificID]);
fprintf(stdout, " Format : %u\n", pCmapFormat.format); // Subtable format; set to 4.
fprintf(stdout, " Length of the subtable : %u bytes\n", pCmapFormat.length); // This is the length in bytes of the subtable.
fprintf(stdout, " Number of Groups : %u\n", pCmapFormat.numGroups); // segCount times 2, minus searchRange ((segCount * 2) - searchRange)
fprintf(stdout, "%s\n", ptrLine_1);
fprintf(stdout, " .....Start Code..... ......End Code...... Identifier .....Start Code..... ......End Code...... Identifier .....Start Code..... ......End Code...... Identifier\n");
fprintf(stdout, " Decimal Unicode Decimal Unicode Start Glyph Decimal Unicode Decimal Unicode Start Glyph Decimal Unicode Decimal Unicode Start Glyph\n");
fprintf(stdout, "%s\n", ptrLine_2);
const short remainder = pCmapFormat.numGroups % 3; // modulus of 3.
const short dividend = pCmapFormat.numGroups / 3; // modulus of 3.
const uint16_t groupLHS = dividend + (remainder == 1 || remainder == 2); // Group at left hand side.
const uint16_t groupMid = dividend + (remainder == 2); // Group at middle.
const uint16_t groupRHS = dividend; // Group at right hand side.
for (uint32_t ii=0, jj=0, kk=0; ii < groupLHS; ii++, jj++, kk++) {
fprintf(stdout, " %3d) %-7u %*cU+%06X %*c%-7u %*cU+%06X %*c%7u",
ii + 1,
pGroupRecord[ii].startCharCode, // Starting character code for each segment.
4, cSP, pGroupRecord[ii].startCharCode, // Unicode Point.
5, cSP, pGroupRecord[ii].endCharCode, // Ending character code for each segment, last = 0xFFFF.
4, cSP, pGroupRecord[ii].endCharCode, // Unicode Point.
9, cSP, pGroupRecord[ii].startGlyphID // Glyph index corresponding to the starting character code. subsequent charcters are mapped to sequential glyphs
);
if (jj < groupMid) {
uint16_t mm = groupLHS + jj;
fprintf(stdout, "%*c %3d) %-7u %*cU+%06X %*c%-7u %*cU+%06X %*c%7u",
10, cSP,
mm + 1,
pGroupRecord[mm].startCharCode, // Starting character code for each segment.
4, cSP, pGroupRecord[mm].startCharCode, // Unicode Point.
5, cSP, pGroupRecord[mm].endCharCode, // Ending character code for each segment, last = 0xFFFF.
4, cSP, pGroupRecord[mm].endCharCode, // Unicode Point.
9, cSP, pGroupRecord[mm].startGlyphID // Glyph index corresponding to the starting character code. subsequent charcters are mapped to sequential glyphs
);
}
if (kk < groupRHS) {
uint16_t nn = groupLHS + groupMid + kk;
fprintf(stdout, "%*c %3d) %-7u %*cU+%06X %*c%-7u %*cU+%06X %*c%7u\n",
10, cSP,
nn + 1,
pGroupRecord[nn].startCharCode, // Starting character code for each segment.
4, cSP, pGroupRecord[nn].startCharCode, // Unicode Point.
5, cSP, pGroupRecord[nn].endCharCode, // Ending character code for each segment, last = 0xFFFF.
4, cSP, pGroupRecord[nn].endCharCode, // Unicode Point.
9, cSP, pGroupRecord[nn].startGlyphID // Glyph index corresponding to the starting character code. subsequent charcters are mapped to sequential glyphs
);
}
else fprintf(stdout, "\n");
}
fprintf(stdout, "%s\n", ptrLine_1);
fprintf(stdout, "\nHit any key to continue.....\n"); getchar();
}
short getNameRecord(const STTFNameRecord* pNameRecordList, const uint16_t pNameRecordCount, const uint16_t pPlatformID, const uint16_t pNameIdentifier)
{
//
// This functions returns the record number corresponding to the pPlatformID and pNameIdentifier
//
// 1. pNameRecordList is an array of input parameter supplying Name-record details.
// 2. pNameRecordCount is an input parameter indicating total number of Name records in the table.
// 3. pPlatformID is an input parameter indicating the platform which are 0=unicode, 1=Macintosh, 2=reserved and 3=Microsoft.
// 4. pNameIdentifier is an input parameter indicating the identifiers which are 0=Copyright, 1=Family, 2=Subfamily, 3=A unique identifier, 4=Font Full name, 5=Version , 6=PostScript, 7=Trademark and so on.
//
for (uint16_t ii = 0; ii < pNameRecordCount; ii++) {
if (pNameRecordList[ii].platformID == pPlatformID && pNameRecordList[ii].nameID == pNameIdentifier) return ii;
}
return -1; // not found.
}
short getPlatform(const STTFCmapTable_Encoding* pCmapSubTableList, const uint16_t pNumOfTables, const uint16_t pPlatformID, const uint16_t pPlatformSpecificID)
{
for (uint16_t ii = 0; ii < pNumOfTables; ii++) {
if (pCmapSubTableList[ii].platformID == pPlatformID && pCmapSubTableList[ii].platformSpecificID == pPlatformSpecificID) return ii;
}
return -1; // not found.
}
short getTable(const STTFTableDirectory * pListOfTables, const uint16_t pTotalDir, const char *pSearchTag)
{
for (short ii = 0; ii < pTotalDir; ii++) {
char tag[5];
sprintf_s(tag, 5, "%.*s", 4, pListOfTables[ii].tag);
if (!_stricmp(tag, pSearchTag)) return ii; // success
}
return -1; // not found.
}
const char *getWeight(const uint16_t pWeightClass)
{
static const char* asWeightClass[] = {
"Error",
"Thin", "Extra-light", "Light", "Regular", "Medium", "Semi-bold", "Bold", "Extra-bold", "Black" // 9 elements.
};
const char* ptrWeightClass;
switch (pWeightClass) {
case 100: ptrWeightClass = asWeightClass[1]; break; // Thin
case 200: ptrWeightClass = asWeightClass[2]; break; // Extra-light (Ultra-light)
case 300: ptrWeightClass = asWeightClass[3]; break; // Light
case 400: ptrWeightClass = asWeightClass[4]; break; // Normal(Regular)
case 500: ptrWeightClass = asWeightClass[5]; break; // Medium
case 600: ptrWeightClass = asWeightClass[6]; break; // Semi-bold (Demi-bold)
case 700: ptrWeightClass = asWeightClass[7]; break; // Bold
case 800: ptrWeightClass = asWeightClass[8]; break; // Extra-bold (Ultra-bold)
case 900: ptrWeightClass = asWeightClass[9]; break; // Black (Heavy)
default: ptrWeightClass = asWeightClass[0]; break; // Error
}
return ptrWeightClass;
}
void writeHexData(FILE* fcid, const char* pData, const uint32_t pLengthOfData)
{
//
// Ths function embeds the table data within angle brackets and write into file.
// i) Table data is embedded as Hexadecimal characters. i.e., each byte will be represented by two Hex digits whose range is from 0 to F.
// ii) Make sure that table data aligns at long boundary (4 byes). Append enough pads ("00") in order to align on long boundary.
// iii) Before closing angle bracket, append "00" in order to make length of table data odd.
//
// 1) fcid is file pointer of type FILE. The table data is dumped into this file as Hex strings covered with angle brackets.
// 2) pData is an input parameter that points to data. This is in decimal form. This will be converted to Hex characters and then will be written ino file.
// 3) pLengthOfData an input parameter indicating the data length in bytes.
//
// This function returns nothing.
//
const short lcBytesPerLine = 38;
fprintf(fcid, "<"); // Begin printing of Hex data with angle bracket.
uint32_t ii = 0; // flush
do {
fprintf(fcid, "%02X", pData[ii++] & 0xff); // Begin printing of Hex data with opening angle bracket.
if (!(ii % lcBytesPerLine)) fprintf(fcid, "\n"); // Continue printing in next line after multiples of lcBytesPerLine.
} while (ii < pLengthOfData);
short residualBytes = pLengthOfData % 4; // Table Data should be aligned at long boundary (4 bytes).
if (residualBytes) residualBytes = 4 - residualBytes; // Additional bytes required to make Table Data to align at long boundary.