Full support of UTF-8 text for PostScript printing/output in 2 ways:
- Latin characters (unicode <= 17F) and a few other symbols, among which the € (Euro), are output using vectorial fonts - All other characters are output as a bitmap copy of their offscreen rendition. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@7697 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
parent
3b3197a86a
commit
c0a8d44710
@ -40,9 +40,23 @@
|
||||
/**
|
||||
\brief PostScript graphical backend.
|
||||
*
|
||||
PostScript text output is presently implemented only for the latin character set.
|
||||
FLTK's standard fonts are output using PostScript's standard fonts: Helvetica, Courier,
|
||||
Times (and their bold, oblique, italic variants), Symbol, ZapfDingbats.
|
||||
PostScript text uses vectorial fonts for the latin alphabet only (exactly: all unicode
|
||||
characters between U+0020 and U+017F, that is, ASCII, Latin-1 Supplement and Latin Extended-A charts)
|
||||
plus a few other punctuation and symbols:
|
||||
U+0192 (ƒ florin), U+02C6 (ˆ circumflex), U+02C7 (ˇ caron),
|
||||
U+02D8 (breve), U+02D9 (dotaccent), U+02DA (ring), U+02DB (ogonek), U+02DC (tilde), U+02DD (hungarumlaut),
|
||||
U+2013 (– endash), U+2014 (— emdash), U+2018 (‘ quoteleft), U+2019 (’ quoteright),
|
||||
U+201A (‚ quotesinglbase), U+201C (“ quotedblleft), U+201D (” quotedblright), U+0201E („ quotedblbase),
|
||||
U+2020 († dagger), U+2021 (‡ daggerdbl), U+2022 (• bullet),
|
||||
U+2026 (… ellipsis), U+2030 (‰ perthousand), U+2039 (‹ guilsinglleft), U+203A (› guilsinglright),
|
||||
U+2044 (⁄ fraction), U+20AC (€ Euro), U+2122 (™ trademark),
|
||||
U+2202 (∂ partialdiff), U+2206 (Δ Delta), U+2211 (∑ summation), U+0221A (√ radical),
|
||||
U+221E (∞ infinity), U+2260 (≠ notequal), U+2264 (≤ lessequal),
|
||||
U+2265 (≥ greaterequal),
|
||||
U+25CA (◊ lozenge), U+FB01 (fi), U+FB02 (fl), U+F8FF ( apple symbol, Mac OS X only).
|
||||
<br> All other unicode characters are output as a bitmap.
|
||||
<br> FLTK standard fonts are output using PostScript standard fonts: Helvetica, Courier,
|
||||
Times (and their bold, oblique, italic variants).
|
||||
*/
|
||||
class Fl_PostScript_Graphics_Driver : public Fl_Graphics_Driver {
|
||||
public:
|
||||
|
@ -349,23 +349,87 @@ static const char * prolog_2 = // prolog relevant only if lang_level >1
|
||||
"end\n"
|
||||
"IDD image GR} bind def\n"
|
||||
|
||||
// procedure to modify a font to use ISOLatin1 encoding (iso-8859-1)
|
||||
// and to keep its name unchanged
|
||||
"/ToLatin1 { dup findfont dup length dict "
|
||||
"begin {def} forall /Encoding ISOLatin1Encoding def currentdict end definefont pop } def\n"
|
||||
// modify all fonts to use ISOLatin1 encoding
|
||||
"/Helvetica ToLatin1 "
|
||||
"/Helvetica-Bold ToLatin1 "
|
||||
"/Helvetica-Oblique ToLatin1 "
|
||||
"/Helvetica-BoldOblique ToLatin1 \n"
|
||||
"/Courier ToLatin1 "
|
||||
"/Courier-Bold ToLatin1 "
|
||||
"/Courier-Oblique ToLatin1 "
|
||||
"/Courier-BoldOblique ToLatin1 \n"
|
||||
"/Times ToLatin1 "
|
||||
"/Times-Bold ToLatin1 "
|
||||
"/Times-Italic ToLatin1 "
|
||||
"/Times-BoldItalic ToLatin1 \n"
|
||||
// Create a custom PostScript font derived from PostScript standard text fonts
|
||||
// The encoding of this custom font is as follows:
|
||||
// 0000-00FF coincides with Unicode, that is to ASCII + Latin-1
|
||||
// 0100-017F coincides with Unicode, that is to Latin Extended-A
|
||||
// 0180-01A6 encodes miscellaneous characters present in PostScript standard text fonts
|
||||
|
||||
// use ISOLatin1Encoding for all text fonts
|
||||
"/ToISO { dup findfont dup length dict copy begin /Encoding ISOLatin1Encoding def currentdict end definefont pop } def\n"
|
||||
"/Helvetica ToISO /Helvetica-Bold ToISO /Helvetica-Oblique ToISO /Helvetica-BoldOblique ToISO \n"
|
||||
"/Courier ToISO /Courier-Bold ToISO /Courier-Oblique ToISO /Courier-BoldOblique ToISO \n"
|
||||
"/Times-Roman ToISO /Times-Bold ToISO /Times-Italic ToISO /Times-BoldItalic ToISO \n"
|
||||
|
||||
// define LatinExtA, the encoding of Latin-extended-A + some additional characters
|
||||
// see http://www.adobe.com/devnet/opentype/archives/glyphlist.txt for their names
|
||||
"/LatinExtA \n"
|
||||
"[ "
|
||||
" /Amacron /amacron /Abreve /abreve /Aogonek /aogonek\n" // begin of Latin Extended-A code page
|
||||
" /Cacute /cacute /Ccircumflex /ccircumflex /Cdotaccent /cdotaccent /Ccaron /ccaron \n"
|
||||
" /Dcaron /dcaron /Dcroat /dcroat\n"
|
||||
" /Emacron /emacron /Ebreve /ebreve /Edotaccent /edotaccent /Eogonek /eogonek /Ecaron /ecaron\n"
|
||||
" /Gcircumflex /gcircumflex /Gbreve /gbreve /Gdotaccent /gdotaccent /Gcommaaccent /gcommaaccent \n"
|
||||
" /Hcircumflex /hcircumflex /Hbar /hbar \n"
|
||||
" /Itilde /itilde /Imacron /imacron /Ibreve /ibreve /Iogonek /iogonek /Idotaccent /dotlessi \n"
|
||||
" /IJ /ij /Jcircumflex /jcircumflex\n"
|
||||
" /Kcommaaccent /kcommaaccent /kgreenlandic \n"
|
||||
" /Lacute /lacute /Lcommaaccent /lcommaaccent /Lcaron /lcaron /Ldotaccent /ldotaccent /Lslash /lslash \n"
|
||||
" /Nacute /nacute /Ncommaaccent /ncommaaccent /Ncaron /ncaron /napostrophe /Eng /eng \n"
|
||||
" /Omacron /omacron /Obreve /obreve /Ohungarumlaut /ohungarumlaut /OE /oe \n"
|
||||
" /Racute /racute /Rcommaaccent /rcommaaccent /Rcaron /rcaron \n"
|
||||
" /Sacute /sacute /Scircumflex /scircumflex /Scedilla /scedilla /Scaron /scaron \n"
|
||||
" /Tcommaaccent /tcommaaccent /Tcaron /tcaron /Tbar /tbar \n"
|
||||
" /Utilde /utilde /Umacron /umacron /Ubreve /ubreve /Uring /uring /Uhungarumlaut /uhungarumlaut /Uogonek /uogonek \n"
|
||||
" /Wcircumflex /wcircumflex /Ycircumflex /ycircumflex /Ydieresis \n"
|
||||
" /Zacute /zacute /Zdotaccent /zdotaccent /Zcaron /zcaron \n"
|
||||
" /longs \n" // end of Latin Extended-A code page
|
||||
" /florin /circumflex /caron /breve /dotaccent /ring \n" // remaining characters from PostScript standard text fonts
|
||||
" /ogonek /tilde /hungarumlaut /endash /emdash \n"
|
||||
" /quoteleft /quoteright /quotesinglbase /quotedblleft /quotedblright \n"
|
||||
" /quotedblbase /dagger /daggerdbl /bullet /ellipsis \n"
|
||||
" /perthousand /guilsinglleft /guilsinglright /fraction /Euro \n"
|
||||
" /trademark /partialdiff /Delta /summation /radical \n"
|
||||
" /infinity /notequal /lessequal /greaterequal /lozenge \n"
|
||||
" /fi /fl /apple \n"
|
||||
" ] def \n"
|
||||
// deal with alternative PostScript names of some characters
|
||||
" /mycharstrings /Helvetica findfont /CharStrings get def\n"
|
||||
" /PSname2 { dup mycharstrings exch known {LatinExtA 3 -1 roll 3 -1 roll put}{pop pop} ifelse } def \n"
|
||||
" 16#20 /Gdot PSname2 16#21 /gdot PSname2 16#30 /Idot PSname2 16#3F /Ldot PSname2 16#40 /ldot PSname2 16#7F /slong PSname2 \n"
|
||||
|
||||
// proc that gives LatinExtA encoding to a font
|
||||
"/ToLatinExtA { findfont dup length dict copy begin /Encoding LatinExtA def currentdict end definefont pop } def\n"
|
||||
// create Ext-versions of standard fonts that use LatinExtA encoding \n"
|
||||
"/HelveticaExt /Helvetica ToLatinExtA \n"
|
||||
"/Helvetica-BoldExt /Helvetica-Bold ToLatinExtA /Helvetica-ObliqueExt /Helvetica-Oblique ToLatinExtA \n"
|
||||
"/Helvetica-BoldObliqueExt /Helvetica-BoldOblique ToLatinExtA \n"
|
||||
"/CourierExt /Courier ToLatinExtA /Courier-BoldExt /Courier-Bold ToLatinExtA \n"
|
||||
"/Courier-ObliqueExt /Courier-Oblique ToLatinExtA /Courier-BoldObliqueExt /Courier-BoldOblique ToLatinExtA \n"
|
||||
"/Times-RomanExt /Times-Roman ToLatinExtA /Times-BoldExt /Times-Bold ToLatinExtA \n"
|
||||
"/Times-ItalicExt /Times-Italic ToLatinExtA /Times-BoldItalicExt /Times-BoldItalic ToLatinExtA \n"
|
||||
|
||||
// proc to create a Type 0 font with 2-byte encoding
|
||||
// that merges a text font with ISO encoding + same font with LatinExtA encoding
|
||||
"/To2byte { 6 dict begin /FontType 0 def \n"
|
||||
"/FDepVector 3 1 roll findfont exch findfont 2 array astore def \n"
|
||||
"/FontMatrix [1 0 0 1 0 0] def /FMapType 6 def /Encoding [ 0 1 0 ] def\n"
|
||||
// 100: Hexa count of ISO array; A7: hexa count of LatinExtA array
|
||||
"/SubsVector < 01 0100 00A7 > def\n"
|
||||
"currentdict end definefont pop } def\n"
|
||||
// create Type 0 versions of standard fonts
|
||||
"/Helvetica2B /HelveticaExt /Helvetica To2byte \n"
|
||||
"/Helvetica-Bold2B /Helvetica-BoldExt /Helvetica-Bold To2byte \n"
|
||||
"/Helvetica-Oblique2B /Helvetica-ObliqueExt /Helvetica-Oblique To2byte \n"
|
||||
"/Helvetica-BoldOblique2B /Helvetica-BoldObliqueExt /Helvetica-BoldOblique To2byte \n"
|
||||
"/Courier2B /CourierExt /Courier To2byte \n"
|
||||
"/Courier-Bold2B /Courier-BoldExt /Courier-Bold To2byte \n"
|
||||
"/Courier-Oblique2B /Courier-ObliqueExt /Courier-Oblique To2byte \n"
|
||||
"/Courier-BoldOblique2B /Courier-BoldObliqueExt /Courier-BoldOblique To2byte \n"
|
||||
"/Times-Roman2B /Times-RomanExt /Times-Roman To2byte \n"
|
||||
"/Times-Bold2B /Times-BoldExt /Times-Bold To2byte \n"
|
||||
"/Times-Italic2B /Times-ItalicExt /Times-Italic To2byte \n"
|
||||
"/Times-BoldItalic2B /Times-BoldItalicExt /Times-BoldItalic To2byte \n"
|
||||
;
|
||||
|
||||
static const char * prolog_2_pixmap = // prolog relevant only if lang_level == 2 for pixmaps/masked color images
|
||||
@ -875,21 +939,21 @@ void Fl_PostScript_Graphics_Driver::line_style(int style, int width, char* dashe
|
||||
};
|
||||
|
||||
static const char *_fontNames[] = {
|
||||
"Helvetica",
|
||||
"Helvetica-Bold",
|
||||
"Helvetica-Oblique",
|
||||
"Helvetica-BoldOblique",
|
||||
"Courier",
|
||||
"Courier-Bold",
|
||||
"Courier-Oblique",
|
||||
"Courier-BoldOblique",
|
||||
"Times",
|
||||
"Times-Bold",
|
||||
"Times-Italic",
|
||||
"Times-BoldItalic",
|
||||
"Helvetica2B",
|
||||
"Helvetica-Bold2B",
|
||||
"Helvetica-Oblique2B",
|
||||
"Helvetica-BoldOblique2B",
|
||||
"Courier2B",
|
||||
"Courier-Bold2B",
|
||||
"Courier-Oblique2B",
|
||||
"Courier-BoldOblique2B",
|
||||
"Times-Roman2B",
|
||||
"Times-Bold2B",
|
||||
"Times-Italic2B",
|
||||
"Times-BoldItalic2B",
|
||||
"Symbol",
|
||||
"Courier",
|
||||
"Courier-Bold",
|
||||
"Courier2B",
|
||||
"Courier-Bold2B",
|
||||
"ZapfDingbats"
|
||||
};
|
||||
|
||||
@ -929,28 +993,136 @@ void Fl_PostScript_Graphics_Driver::draw(int angle, const char *str, int n, int
|
||||
fprintf(output, "GR\n");
|
||||
}
|
||||
|
||||
// outputs in PostScript a UTF8 string replacing non-Latin1 characters by ?
|
||||
// and using the same width in points as on display
|
||||
void Fl_PostScript_Graphics_Driver::transformed_draw(const char* str, int n, double x, double y) {
|
||||
int len;
|
||||
if (!n || !str || !*str) return;
|
||||
const char *last = str + n;
|
||||
// compute display width of string
|
||||
fprintf(output,"%g (", fl_width(str, n));
|
||||
while (str < last) {
|
||||
// Extract each unicode character of string.
|
||||
// Until 0xFF, UTF codes coincide with iso-Latin1 (iso-8859-1)
|
||||
unsigned utf = fl_utf8decode(str, last, &len);
|
||||
str += len;
|
||||
if (utf > 0xFF) {
|
||||
utf = '?'; // replace non Latin-1 unicodes by ?
|
||||
|
||||
// computes the mask for the RGB image img of all pixels with color != bg
|
||||
static uchar *calc_mask(uchar *img, int w, int h, Fl_Color bg)
|
||||
{
|
||||
uchar red, green, blue, r, g, b;
|
||||
uchar bit, byte, *q;
|
||||
Fl::get_color(bg, red, green, blue);
|
||||
int W = (w+7)/8; // width of mask
|
||||
uchar* mask = new uchar[W * h];
|
||||
q = mask;
|
||||
while (h-- > 0) { // for each row
|
||||
bit = 0x80; // byte with last bit set
|
||||
byte = 0; // next mask byte to compute
|
||||
for (int j = 0; j < w; j++) { // for each column
|
||||
r = *img++; // the pixel color components
|
||||
g = *img++;
|
||||
b = *img++;
|
||||
// if pixel doesn't have bg color, put it in mask
|
||||
if (r != red || g != green || b != blue) byte |= bit;
|
||||
bit = bit>>1; // shift bit one step to the right
|
||||
if (bit == 0) { // single set bit has fallen out
|
||||
*q++ = byte; // enter byte in mask
|
||||
byte = 0; // reset next mask byte to zero
|
||||
bit = 0x80; // and this byte
|
||||
}
|
||||
}
|
||||
else if (utf == '(' || utf == ')' || utf == '\\') {
|
||||
putc('\\' , output); // these chars need be escaped
|
||||
}
|
||||
putc(utf, output); // output the latin character
|
||||
if (bit != 0x80) *q++ = byte; // enter last columns' byte in mask
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
// write to PostScript a bitmap image of a UTF8 string
|
||||
static void transformed_draw_extra(const char* str, int n, double x, double y, int w, FILE *output) {
|
||||
const float scale = 3; // scale for bitmask computation
|
||||
Fl_Fontsize old_size = fl_size();
|
||||
fl_font(fl_font(), (Fl_Fontsize)(scale * old_size) );
|
||||
w = (int)(w *scale + 0.5);
|
||||
int h = fl_height();
|
||||
// create an offscreen image of the string
|
||||
Fl_Color text_color = fl_color();
|
||||
Fl_Color bg_color = fl_contrast(FL_WHITE, text_color);
|
||||
Fl_Offscreen off = fl_create_offscreen(w+2, (int)(h+3*scale) );
|
||||
fl_begin_offscreen(off);
|
||||
fl_color(bg_color);
|
||||
// color offscreen background with a shade contrasting with the text color
|
||||
fl_rectf(0, 0, w+2, (int)(h+3*scale) );
|
||||
fl_color(text_color);
|
||||
fl_draw(str, n, 1, (int)(h * 0.8) ); // draw string in offscreen
|
||||
// read (most of) the offscreen image
|
||||
uchar *img = fl_read_image(NULL, 1, 1, w, h, 0);
|
||||
fl_end_offscreen();
|
||||
fl_font(fl_font(), old_size);
|
||||
fl_delete_offscreen(off);
|
||||
// compute the mask of what is not the background
|
||||
uchar *mask = calc_mask(img, w, h, bg_color);
|
||||
delete img;
|
||||
// write the string image to PostScript as a scaled bitmask
|
||||
fprintf(output, "%g %g %g %g %d %d MI\n", x, y - h*0.77/scale, w/scale, h/scale, w, h);
|
||||
uchar *di;
|
||||
int wmask = (w+7)/8;
|
||||
for (int j = h - 1; j >= 0; j--){
|
||||
di = mask + j * wmask;
|
||||
for (int i = 0; i < wmask; i++){
|
||||
//if (!(i%80)) fprintf(output, "\n"); // don't have lines longer than 255 chars
|
||||
fprintf(output, "%2.2x", *di );
|
||||
di++;
|
||||
}
|
||||
fprintf(output,"\n");
|
||||
}
|
||||
fprintf(output, ") %g %g show_pos_width\n", x, y);
|
||||
fprintf(output,">\n");
|
||||
delete mask;
|
||||
}
|
||||
|
||||
static int is_in_table(unsigned utf) {
|
||||
unsigned i;
|
||||
static unsigned extra_table_roman[] = { // unicodes/*names*/ of other characters from PostScript standard fonts
|
||||
0x192/*florin*/, 0x2C6/*circumflex*/, 0x2C7/*caron*/,
|
||||
0x2D8/*breve*/, 0x2D9/*dotaccent*/, 0x2DA/*ring*/, 0x2DB/*ogonek*/, 0x2DC/*tilde*/, 0x2DD/*hungarumlaut*/,
|
||||
0x2013/*endash*/, 0x2014/*emdash*/, 0x2018/*quoteleft*/, 0x2019/*quoteright*/,
|
||||
0x201A/*quotesinglbase*/, 0x201C/*quotedblleft*/, 0x201D/*quotedblright*/, 0x201E/*quotedblbase*/,
|
||||
0x2020/*dagger*/, 0x2021/*daggerdbl*/, 0x2022/*bullet*/,
|
||||
0x2026/*ellipsis*/, 0x2030/*perthousand*/, 0x2039/*guilsinglleft*/, 0x203A/*guilsinglright*/,
|
||||
0x2044/*fraction*/, 0x20AC/*Euro*/, 0x2122/*trademark*/,
|
||||
0x2202/*partialdiff*/, 0x2206/*Delta*/, 0x2211/*summation*/, 0x221A/*radical*/,
|
||||
0x221E/*infinity*/, 0x2260/*notequal*/, 0x2264/*lessequal*/,
|
||||
0x2265/*greaterequal*/,
|
||||
0x25CA/*lozenge*/, 0xFB01/*fi*/, 0xFB02/*fl*/,
|
||||
0xF8FF/*apple*/
|
||||
};
|
||||
for ( i = 0; i < sizeof(extra_table_roman)/sizeof(int); i++) {
|
||||
if (extra_table_roman[i] == utf) return i + 0x180;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// outputs in PostScript a UTF8 string using the same width in points as on display
|
||||
void Fl_PostScript_Graphics_Driver::transformed_draw(const char* str, int n, double x, double y) {
|
||||
int len, code;
|
||||
if (!n || !str || !*str) return;
|
||||
// compute display width of string
|
||||
int width = (int)fl_width(str, n);
|
||||
if (width == 0) return;
|
||||
fprintf(output, "%d <", width);
|
||||
// transforms UTF8 encoding to our custom PostScript encoding as follows:
|
||||
// extract each unicode character
|
||||
// if unicode <= 0x17F, unicode and PostScript codes are identical
|
||||
// if unicode is one of the values listed in extra_table_roman above
|
||||
// its PostScript code is 0x180 + the character's rank in extra_table_roman
|
||||
// if unicode is something else, draw all string as bitmap image
|
||||
|
||||
const char *last = str + n;
|
||||
const char *str2 = str;
|
||||
while (str2 < last) {
|
||||
// Extract each unicode character of string.
|
||||
unsigned utf = fl_utf8decode(str2, last, &len);
|
||||
str2 += len;
|
||||
if (utf <= 0x17F) { // until Latin Extended-A
|
||||
;
|
||||
}
|
||||
else if ( (code = is_in_table(utf)) != 0) { // other handled characters
|
||||
utf = code;
|
||||
}
|
||||
else { // unhandled character: draw all string as bitmap image
|
||||
fprintf(output, "> pop pop\n"); // close and ignore the opened hex string
|
||||
transformed_draw_extra(str, n, x, y, width, output);
|
||||
return;
|
||||
}
|
||||
fprintf(output, "%4.4X", utf);
|
||||
}
|
||||
fprintf(output, "> %g %g show_pos_width\n", x, y);
|
||||
}
|
||||
|
||||
struct matrix {double a, b, c, d, x, y;};
|
||||
|
Loading…
Reference in New Issue
Block a user