developing new draw

git-svn-id: svn://ultimatepp.org/upp/trunk@1373 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2009-07-06 20:31:59 +00:00
parent fa47b4615a
commit f67d0a41eb
47 changed files with 1913 additions and 0 deletions

21
uppsrc/PdfDraw/Copying Normal file
View file

@ -0,0 +1,21 @@
Copyright 1998-2008 The U++ Project. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE U++ PROJECT ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.

834
uppsrc/PdfDraw/PdfDraw.cpp Normal file
View file

@ -0,0 +1,834 @@
#include "PdfDraw.h"
NAMESPACE_UPP
#define LDUMP(x) // DUMP(x)
#define LLOG(x) // LOG(x)
#define PDF_COMPRESS
#define USE_TTF
dword PdfDraw::GetInfo() const
{
return DOTS;
}
Size PdfDraw::GetPageSize() const
{
return pgsz;
}
void PdfDraw::Init(int pagecx, int pagecy, int _margin)
{
Clear();
margin = _margin;
pgsz.cx = pagecx;
pgsz.cy = pagecy;
pgsz += margin;
}
void PdfDraw::Clear()
{
out.Clear();
page.Clear();
offset.Clear();
out << "%PDF-1.3\n";
out << "%\xf1\xf2\xf3\xf4\n\n";
}
int PdfDraw::BeginObj()
{
offset.Add(out.GetLength());
out << offset.GetCount() << " 0 obj\n";
return offset.GetCount();
}
void PdfDraw::EndObj()
{
out << "endobj\n\n";
}
void PdfDraw::PutRect(const Rect& rc)
{
page << Pt(rc.left) << ' ' << Pt(pgsz.cy - rc.bottom) << ' '
<< Pt(rc.Width()) << ' ' << Pt(rc.Height()) << " re\n";
}
int PdfDraw::PutStream(const String& data, const String& keys)
{
#ifdef PDF_COMPRESS
String c = ZCompress(data);
if(c.GetLength() < data.GetLength()) {
BeginObj();
out << "<< " << keys
<< "/Length " << c.GetLength() << " "
<< "/Length1 " << data.GetLength() << " "
<< "/Filter /FlateDecode "
<< " >>\n"
<< "stream\r\n" << c << "\r\nendstream\n";
EndObj();
return offset.GetCount();
}
#endif
BeginObj();
out << "<< " << keys << " /Length " << data.GetLength() <<
" /Length1 "<< data.GetLength() << " >>\n"
<< "stream\r\n" << data << "\r\nendstream\n";
EndObj();
return offset.GetCount();
}
void PdfDraw::PutrgColor(Color rg)
{
if(IsNull(rgcolor) || rg != rgcolor)
page << PdfColor(rgcolor = rg) << " rg\n";
}
void PdfDraw::PutRGColor(Color RG)
{
if(IsNull(RGcolor) || RG != RGcolor)
page << PdfColor(RGcolor = RG) << " RG\n";
}
void PdfDraw::PutLineWidth(int lw)
{
lw = max(Nvl(lw, 0), 5);
if(linewidth != lw)
page << Pt(linewidth = lw) << " w\n";
}
void PdfDraw::StartPage()
{
rgcolor = RGcolor = Null;
fontid = -1;
textht = Null;
linewidth = -1;
if(margin)
OffsetOp(Point(margin, margin));
}
void PdfDraw::EndPage()
{
if(margin)
EndOp();
PutStream(page);
page.Clear();
}
void PdfDraw::BeginOp()
{
page << "q\n";
}
void PdfDraw::EndOp()
{
fontid = -1;
textht = Null;
rgcolor = RGcolor = Null;
linewidth = -1;
page << "Q\n";
}
void PdfDraw::OffsetOp(Point p)
{
page << "q ";
if(p.x || p.y)
page << "1 0 0 1 " << Pt(p.x) << ' ' << Pt(-p.y) << " cm\n";
}
bool PdfDraw::ClipOp(const Rect& r)
{
page << "q ";
PutRect(r);
page << "W* n\n";
return true;
}
bool PdfDraw::ClipoffOp(const Rect& r)
{
page << "q ";
PutRect(r);
page << "W* n\n";
if(r.left || r.top)
page << "1 0 0 1 " << Pt(r.left) << ' ' << Pt(-r.top) << " cm\n";
return true;
}
bool PdfDraw::ExcludeClipOp(const Rect& r)
{
return true; // TODO
/*
if(r.left <= actual_clip.left && r.right >= actual_clip.right) {
if(r.top <= actual_clip.top) actual_clip.top = max(actual_clip.top, r.bottom);
if(r.bottom >= actual_clip.bottom) actual_clip.bottom = min(actual_clip.bottom, r.top);
}
if(r.top <= actual_clip.top && r.bottom >= actual_clip.bottom) {
if(r.left <= actual_clip.left) actual_clip.left = max(actual_clip.left, r.right);
if(r.right >= actual_clip.right) actual_clip.right = min(actual_clip.right, r.left);
}
PutRect(actual_clip);
PutRect(r & actual_clip);
page << "W* n\n";
return !actual_clip.IsEmpty();
*/
}
bool PdfDraw::IntersectClipOp(const Rect& r)
{
PutRect(r);
page << "W* n\n";
return true;
}
bool PdfDraw::IsPaintingOp(const Rect&) const
{
return true;
}
PdfDraw::CharPos PdfDraw::GetCharPos(Font fnt, wchar chr)
{
fnt.Underline(false);
VectorMap<wchar, CharPos>& fc = fontchars.GetAdd(fnt);
int q = fc.Find(chr);
if(q >= 0)
return fc[q];
CharPos& p = fc.Add(chr);
q = pdffont.FindLast(fnt);
if(q < 0 || pdffont[q].GetCount() > 250) {
p.fi = pdffont.GetCount();
p.ci = 0;
pdffont.Add(fnt).Add(chr);
}
else {
p.fi = q;
p.ci = pdffont[q].GetCount();
pdffont[q].Add(chr);
}
return p;
}
void PdfDraw::FlushText(int dx, int fi, int height, const String& txt)
{
if(fi < 0)
return;
if(dx)
page << Pt(dx) << " 0 Td ";
PutFontHeight(fi, height);
page << "<" << txt << "> Tj\n";
}
String PdfDraw::PdfColor(Color c)
{
return NFormat("%3nf %3nf %3nf", c.GetR() / 255.0, c.GetG() / 255.0, c.GetB() / 255.0);
}
void PdfDraw::PutFontHeight(int fi, double ht)
{
if(fi != fontid || IsNull(textht) || ht != textht)
page << "/F" << ((fontid = fi) + 1) << ' ' << Pt(textht = ht) << " Tf\n";
}
PdfDraw::OutlineInfo PdfDraw::GetOutlineInfo(Font fnt)
{
fnt.Height(0);
int q = outline_info.Find(fnt);
if(q >= 0)
return outline_info[q];
OutlineInfo of;
of.sitalic = of.ttf = false;
#ifdef USE_TTF
#ifdef PLATFORM_WIN32
ScreenDraw info;
info.SetFont(fnt().Underline(false));
TEXTMETRIC tm;
GetTextMetrics(info.GetHandle(), &tm);
if(tm.tmPitchAndFamily & TMPF_TRUETYPE) {
of.ttf = true;
int c = GetOutlineTextMetrics(info.GetHandle(), 0, NULL);
if(c > 0) {
Buffer<byte> h(c);
OUTLINETEXTMETRIC *otm = (OUTLINETEXTMETRIC *)~h;
GetOutlineTextMetrics(info.GetHandle(), c, otm);
of.sitalic = otm->otmItalicAngle == 0 && fnt.IsItalic();
}
}
#endif
#ifdef PLATFORM_X11
FontInfo fi = fnt.Info();
String fn = fi.GetFileName();
String ext = ToLower(GetFileExt(fn));
if(ext == ".ttf" || ext == ".otf") {
String data = LoadFile(fn);
TTFReader ttf;
if(ttf.Open(data, false, true)) {
of.ttf = true;
of.sitalic = ttf.post.italicAngle == 0 && fnt.IsItalic();
}
}
#endif
#endif
outline_info.Add(fnt, of);
return of;
}
void PdfDraw::DrawTextOp(int x, int y, int angle, const wchar *s, Font fnt,
Color ink, int n, const int *dx)
{
if(!n) return;
if(fnt.GetHeight() == 0)
fnt.Height(100);
FontInfo ff = fnt.Info();
#ifdef PLATFORM_WIN32
int fh = ff.GetHeight() - ff.GetInternal();//TODO
#endif
#ifdef PLATFORM_X11
int fh = fnt.GetHeight();
#endif
OutlineInfo of = GetOutlineInfo(fnt);
if(of.ttf)
fnt.Height(0);
String txt;
PutrgColor(ink);
PutRGColor(ink);
page << "BT ";
double sina = 0, cosa = 1;
int posx = 0;
if(angle || dx || (of.sitalic && !fnt.IsItalic())) {
M22 m;
if(of.sitalic)
m.c = 0.165;
if(angle) {
Draw::SinCos(angle, sina, cosa);
m.Mul(cosa, sina, -sina, cosa);
}
int fi = -1;
bool straight = (fabs(m.a - 1) <= 1e-8 && fabs(m.b) <= 1e-8 && fabs(m.c) <= 1e-8 && fabs(m.d - 1) <= 1e-8);
Pointf prev(0, 0);
for(int i = 0; i < n; i++) {
Pointf next(Pt(x + posx * cosa + fround(ff.GetAscent() * sina)),
Pt(pgsz.cy - (y - posx * sina) - fround(ff.GetAscent() * cosa)));
CharPos fp = GetCharPos(fnt, s[i]);
if(fi != fp.fi) {
fi = fp.fi;
PutFontHeight(fi, fh);
}
if(straight)
page << (next.x - prev.x) << ' ' << (next.y - prev.y) << " Td";
else
page << m.a << ' ' << m.b << ' ' << m.c << ' ' << m.d << ' ' << next.x << ' ' << next.y << " Tm";
page << " <" << FormatIntHex(fp.ci, 2);
while(i + 1 < n) {
int cw = ff[s[i]];
if(dx && dx[i] != cw)
break;
posx += cw;
CharPos np = GetCharPos(fnt, s[i + 1]);
if(np.fi != fp.fi)
break;
page << FormatIntHex(np.ci, 2);
i++;
}
page << "> Tj\n";
posx += dx ? dx[i] : ff[s[i]];
prev = next;
}
}
else {
page << Pt(x) << " " << Pt(pgsz.cy - y - ff.GetAscent()) << " Td\n";
int fi = -1;
int ppos = 0;
int np = 0;
for(int i = 0; i < n; i++) {
CharPos fp = GetCharPos(fnt, s[i]);
if(fp.fi != fi) {
FlushText(np, fi, fnt.GetHeight(), txt);
txt.Clear();
np = posx - ppos;
ppos = posx;
fi = fp.fi;
}
txt.Cat(Sprintf("%02.2X", fp.ci));
posx += ff[s[i]];
}
FlushText(np, fi, fh, txt);
}
page << "ET\n";
if(fnt.IsUnderline()) {
int w = ff.GetAscent() / 15;
int dy = ff.GetAscent() + max((ff.GetDescent() - w) / 2, ff.GetAscent() / 10);
DrawLine(fround(x + sina * dy),
fround(y + cosa * dy),
fround(x + cosa * posx + sina * dy),
fround(y + cosa * dy - sina * posx), w, ink);
}
}
Image RenderGlyph(int cx, int x, Font font, int chr, int py, int pcy)
{
ImageDraw iw(cx, pcy);
iw.DrawRect(0, 0, cx, pcy, White);
iw.DrawText(x, -py, WString(chr, 1), font, Black);
return iw;
}
PdfDraw::RGlyph PdfDraw::RasterGlyph(Font fnt, int chr)
{
RGlyph rg;
FontInfo fi = fnt.Info();
rg.x = 0;
rg.sz.cx = fi[chr];
rg.sz.cy = fi.GetHeight();
int l = fi.GetLeftSpace(chr);
if(l < 0) {
rg.x = -l;
rg.sz.cx -= l;
}
int r = fi.GetRightSpace(chr);
if(r < 0)
rg.sz.cx -= r;
RasterFormat fmt;
fmt.Set1mf();
int linebytes = fmt.GetByteCount(rg.sz.cx);
Buffer<byte> ob(linebytes);
int y = 0;
while(y < rg.sz.cy) {
int ccy = min(16, rg.sz.cy - y);
Image m = RenderGlyph(rg.sz.cx, rg.x, fnt, chr, y, ccy);
for(int i = 0; i < m.GetHeight(); i++) {
fmt.Write(ob, m[i], rg.sz.cx, NULL);
rg.data.Cat((const char *)~ob, linebytes);
}
y += ccy;
}
return rg;
}
void PdfDraw::DrawRectOp(int x, int y, int cx, int cy, Color color)
{
if(IsNull(color) || cx <= 0 || cy <= 0) return;
PutrgColor(color);
PutRGColor(color);
PutRect(RectC(x, y, cx, cy));
page << "f\n";
}
void PdfDraw::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color)
{
if(!IsNull(width)) {
PutRGColor(color);
PutLineWidth(width);
page << " 1 J "
<< Pt(x1) << ' ' << Pt(pgsz.cy - y1) << " m "
<< Pt(x2) << ' ' << Pt(pgsz.cy - y2) << " l S\n";
}
}
void PdfDraw::DrawImageOp(int x, int y, int cx, int cy, const Image& _img, const Rect& src, Color c)
{
Image img = _img;
if(!IsNull(c))
img = SetColorKeepAlpha(img, c);
image.Add(img);
imagerect.Add(src);
page << "q "
<< Pt(cx) << " 0 0 " << Pt(cy) << ' '
<< Pt(x) << ' ' << Pt(pgsz.cy - y - cy)
<< " cm /Image" << image.GetCount() << " Do Q\n";
}
void PdfDraw::DrawPolyPolylineOp(const Point *vertices, int vertex_count,
const int *counts, int count_count,
int width, Color color, Color doxor)
{
if(IsNull(color) || IsNull(width))
return;
PutRGColor(color);
PutLineWidth(width);
while(--count_count >= 0) {
int part = *counts++;
page << Pt(vertices->x) << ' ' << Pt(pgsz.cy - vertices->y) << " m\n";
vertices++;
for(; --part > 0; vertices++)
page << Pt(vertices->x) << ' ' << Pt(pgsz.cy - vertices->y) << " l\n";
page << "S\n";
}
}
void PdfDraw::DrawEllipseOp(const Rect& r, Color color, int pen, Color outline)
{
bool fill = !IsNull(color), stroke = !IsNull(outline) && !IsNull(pen);
if(fill) PutrgColor(color);
if(stroke) { PutRGColor(outline); PutLineWidth(pen); }
if(!fill && !stroke)
return;
char closeop = (stroke && fill ? 'B' : fill ? 'f' : 'S');
int sizelim = r.Width() | r.Height();
int bits = 1;
while(bits < 20 && sizelim > (1 << bits))
bits++;
int parts = 3 + max(((bits * (bits - 6)) >> 3) | 1, 1);
double k = 2 * M_PI / 3 / parts;
Pointf center(Pt((r.left + r.right) / 2.0), Pt(pgsz.cy - ((r.top + r.bottom) / 2.0)));
Pointf size(Pt(r.Width() / 2.0), Pt(r.Height() / 2.0));
for(int partid = 0; partid < parts; partid++) {
double phi1 = (partid + 0) * (2 * M_PI / parts);
double phi2 = (partid + 1) * (2 * M_PI / parts);
double s1 = sin(phi1), c1 = cos(phi1), s2 = sin(phi2), c2 = cos(phi2);
Pointf A = center + Pointf(c1, s1) * size;
Pointf D = center + Pointf(c2, s2) * size;
Pointf dA = Pointf(-s1, c1) * size;
Pointf dD = Pointf(-s2, c2) * size;
Pointf B = A + k * dA;
Pointf C = D - k * dD;
if(!partid)
page << FormatDoubleFix(A.x, 2) << ' ' << FormatDoubleFix(A.y, 2) << " m\n";
page << FormatDoubleFix(B.x, 2) << ' ' << FormatDoubleFix(B.y, 2) << ' '
<< FormatDoubleFix(C.x, 2) << ' ' << FormatDoubleFix(C.y, 2) << ' '
<< FormatDoubleFix(D.x, 2) << ' ' << FormatDoubleFix(D.y, 2) << " c\n";
}
page << closeop << '\n';
}
void PdfDraw::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color)
{
//TODO!!
NEVER();
}
void PdfDraw::DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count,
const int *subpolygon_counts, int subpolygon_count_count,
const int *disjunct_polygon_counts, int disjunct_polygon_count_count,
Color color, int width, Color outline, uint64 pattern, Color doxor)
{
bool fill = !IsNull(color), stroke = !IsNull(outline) && !IsNull(width);
if(fill) PutrgColor(color);
if(stroke) { PutRGColor(outline); PutLineWidth(width); }
if(!fill && !stroke) return;
const char *closeop = (fill & stroke ? "B*" : fill ? "f*" : "S");
while(--disjunct_polygon_count_count >= 0) {
int disj = *disjunct_polygon_counts++;
while(disj > 0) {
int sub = *subpolygon_counts++;
disj -= sub;
page << Pt(vertices->x) << ' ' << Pt(pgsz.cy - vertices->y) << " m\n";
vertices++;
for(; --sub > 0; vertices++)
page << Pt(vertices->x) << ' ' << Pt(pgsz.cy - vertices->y) << " l\n";
page << "h\n";
}
page << closeop << '\n';
}
}
String PdfDraw::Finish()
{
if(!IsNull(page))
PutStream(page);
int pagecount = offset.GetCount();
Vector<int> imageobj;
for(int i = 0; i < image.GetCount(); i++) {
Size sz = image[i].GetSize();
Rect sr = sz & imagerect[i];
String data;
const Image& m = image[i];
int mask = -1;
int smask = -1;
if(m.GetKind() == IMAGE_MASK) {
for(int y = sr.top; y < sr.bottom; y++) {
const RGBA *p = m[y] + sr.left;
const RGBA *e = m[y] + sr.right;
while(p < e) {
int bit = 0x80;
byte b = 0;
while(bit && p < e) {
if(p->a != 255)
b |= bit;
bit >>= 1;
p++;
}
data.Cat(b);
}
}
mask = PutStream(data, String().Cat()
<< "/Type /XObject /Subtype /Image /Width " << sr.Width()
<< " /Height " << sr.Height()
<< " /BitsPerComponent 1 /ImageMask true /Decode [0 1]");
}
if(m.GetKind() == IMAGE_ALPHA) {
for(int y = sr.top; y < sr.bottom; y++) {
const RGBA *p = m[y] + sr.left;
const RGBA *e = m[y] + sr.right;
while(p < e)
data.Cat((p++)->a);
}
smask = PutStream(data, String().Cat()
<< "/Type /XObject /Subtype /Image /Width " << sr.Width()
<< " /Height " << sr.Height()
<< " /BitsPerComponent 8 /ColorSpace /DeviceGray /Decode [0 1]");
}
data.Clear();
for(int y = sr.top; y < sr.bottom; y++) {
const RGBA *p = m[y] + sr.left;
const RGBA *e = m[y] + sr.right;
while(p < e) {
data.Cat(p->r);
data.Cat(p->g);
data.Cat(p->b);
p++;
}
}
String imgobj;
imgobj << "/Type /XObject /Subtype /Image /Width " << sr.Width()
<< " /Height " << sr.Height() << " /BitsPerComponent 8 /ColorSpace /DeviceRGB";
if(mask >= 0)
imgobj << " /Mask " << mask << " 0 R";
if(smask >= 0)
imgobj << " /SMask " << smask << " 0 R";
imageobj << PutStream(data, imgobj);
}
/*
Vector<int> rgobj;
Vector<Size> rgsz;
Vector<int> rgx;
for(int i = 0; i < pdffont.GetCount(); i++) {
Font fnt = pdffont.GetKey(i);
if(fnt.GetHeight()) {
for(int c = 0; c < pdffont[i].GetCount(); c++) {
RGlyph rg = RasterGlyph(fnt, pdffont[i][c]);
int ii = rgobj.GetCount();
rgobj << PutStream(rg.data, String().Cat()
<< "/Type /XObject /Subtype /Image "
<< " /Width " << rg.sz.cx << " /Height " << rg.sz.cy
<< " /BitsPerComponent 1 /ImageMask true /Decode [0 1]");
rgsz.Add(rg.sz);
rgx.Add(rg.x);
}
}
}
*/
Vector<int> fontobj;
for(int i = 0; i < pdffont.GetCount(); i++) {
Font fnt = pdffont.GetKey(i);
const Vector<wchar>& cs = pdffont[i];
String cmap;
cmap <<
"/CIDInit /ProcSet findresource begin\n"
"12 dict begin\n"
"begincmap\n"
"/CIDSystemInfo\n"
"<< /Registry (Adobe)\n"
"/Ordering (UCS)\n"
"/Supplement 0\n"
">> def\n"
"/CMapName /UCS" << i << " def\n"
"/CMapType 2 def\n"
"1 begincodespacerange\n"
"<00> <" << FormatIntHex(cs.GetCount() - 1, 2) << ">\n"
"endcodespacerange\n"
"1 beginbfrange\n"
"<00> <" << FormatIntHex(cs.GetCount() - 1, 2) << ">\n"
"[\n";
for(int c = 0; c < cs.GetCount(); c++)
cmap << '<' << FormatIntHex(cs[c], 4) << ">\n";
cmap <<
"]\n"
"endbfrange\n"
"endcmap\n"
"CMapName currentdict /CMap defineresource pop\n"
"end\n"
"end\n";
int cmapi = PutStream(cmap);
if(fnt.GetHeight()) {
FontInfo fi = fnt.Info();
int t3ch = offset.GetCount() + 1;
int fa = fi.GetHeight() - fi.GetInternal();
String res;
for(int c = 0; c < cs.GetCount(); c++) {
RGlyph rg = RasterGlyph(fnt, pdffont[i][c]);
String proc;
proc
<< 1000 * fi[cs[c]] / fa << " 0 0 "
<< -1000 * fi.GetDescent() / fa << ' '
<< 1000 * (rg.sz.cx + rg.x) / fa << ' '
<< 1000 * rg.sz.cy / fa
<< " d1\nq "
<< 1000 * rg.sz.cx / fa
<< " 0 0 "
<< 1000 * rg.sz.cy / fa
<< " "
<< -1000 * rg.x / fa
<< " "
<< -1000 * fi.GetDescent() / fa
<< " cm BI /W " << rg.sz.cx << " /H " << rg.sz.cy
<< " /BPC 1 /IM true /D [0 1] ID\n"
<< rg.data
<< "\nEI Q"
;
PutStream(proc);
}
int charprocs = BeginObj();
out << "<<";
for(int c = 0; c < cs.GetCount(); c++)
out << " /Rgch" << c << ' ' << t3ch + c<< " 0 R";
out << " >>\n";
EndObj();
int encoding = BeginObj();
out << "<< /Type /Encoding /Differences [0";
for(int c = 0; c < cs.GetCount(); c++)
out << " /Rgch" << c;
out << "] >>\n";
EndObj();
fontobj.Add() = BeginObj();
out <<
"<< /Name /F" << i + 1 <<
" /Type /Font\n"
"/Subtype /Type3\n"
"/FontBBox [0 0 0 0]\n"
"/FontMatrix [0.001 0 0 0.001 0 0]\n"
"/CharProcs " << charprocs << " 0 R\n"
"/Encoding " << encoding << " 0 R\n"
"/FirstChar 0\n"
"/LastChar " << cs.GetCount() - 1 << "\n"
"/Widths [";
for(int i = 0; i < cs.GetCount(); i++)
out << ' ' << 1000 * fi[cs[i]] / fa;
out <<
"]\n";
out << "/Resources << /ProcSet [ /PDF /Text /ImageB ] >>\n"
<< "/FirstChar 0 /LastChar " << cs.GetCount() - 1 <<" /ToUnicode "
<< cmapi
<< " 0 R\n>>\n";
EndObj();
}
else {
#ifdef PLATFORM_POSIX
FontInfo fi = pdffont.GetKey(i).Info();
String fontbuffer = LoadFile(fi.GetFileName());
#endif
#ifdef PLATFORM_WIN32
ScreenDraw sd;
sd.SetFont(pdffont.GetKey(i));
int size = GetFontData(sd.GetHandle(), 0, 0, NULL, 0);
if(size == GDI_ERROR) {
LLOG("PdfDraw::Finish: GDI_ERROR on font " << pdffont.GetKey(i));
return Null;
}
StringBuffer fontbuffer(size);
GetFontData(sd.GetHandle(), 0, 0, fontbuffer, size);
#endif
TTFReader ttf;
if(!ttf.Open(fontbuffer))
return Null;
String name = FormatIntAlpha(i + 1, true);
name.Cat('A', 6 - name.GetLength());
name << '+' << ttf.ps_name;
int fonti = PutStream(ttf.Subset(cs));
BeginObj();
int ascent = ttf.hhea.ascent * 1000 / ttf.head.unitsPerEm;
int descent = ttf.hhea.descent * 1000 / ttf.head.unitsPerEm;
out <<
"<< /Type /FontDescriptor\n"
"/FontName /" << name << "\n"
"/Flags 4\n"
"/FontBBox [ -1000 " << descent << " 3000 " << ascent << " ]\n" //?????
"/ItalicAngle " << ttf.post.italicAngle / 65536.0 << "\n"
"/Ascent " << ascent << "\n"
"/Descent " << -descent << "\n"
"/CapHeight " << ttf.hhea.ascent * 1000 / ttf.head.unitsPerEm << "\n"
"/StemV 80\n"
"/FontFile2 " << fonti << " 0 R\n" <<
">>\n";
EndObj();
fontobj.Add() = BeginObj();
out <<
"<< /Type /Font\n"
"/Subtype /TrueType\n"
"/BaseFont /" << name << "\n"
"/FirstChar 0\n"
"/LastChar " << cs.GetCount() - 1 << "\n"
"/Widths [ ";
for(int i = 0; i < cs.GetCount(); i++)
out << ttf.GetAdvanceWidth(cs[i]) * 1000 / ttf.head.unitsPerEm << ' ';
out <<
"]\n"
"/FontDescriptor " << fonti + 1 << " 0 R\n"
"/ToUnicode " << cmapi << " 0 R\n" <<
">>\n";
EndObj();
}
}
int pages = BeginObj();
out << "<< /Type /Pages\n"
<< "/Kids [";
for(int i = 0; i < pagecount; i++)
out << i + pages + 1 << " 0 R ";
out << "]\n"
<< "/Count " << pagecount << "\n"
<< "/Resources << /ProcSet [ /PDF /Text /ImageB /ImageC ]\n";
if(pdffont.GetCount()) {
out << "/Font << ";
for(int i = 0; i < pdffont.GetCount(); i++)
out << "/F" << i + 1 << ' ' << fontobj[i] << " 0 R ";
out << ">>\n";
}
if(!imageobj.IsEmpty()) {
out << "/XObject << ";
for(int i = 0; i < imageobj.GetCount(); i++)
out << "/Image" << i + 1 << ' ' << imageobj[i] << " 0 R ";
out << ">>\n";
}
out << ">> >>\n";
EndObj();
for(int i = 0; i < pagecount; i++) {
BeginObj();
out << "<< /Type /Page\n"
<< "/Parent " << pages << " 0 R\n"
<< "/MediaBox [0 0 " << Pt(pgsz.cx) << ' ' << Pt(pgsz.cy) << "]\n"
<< "/Contents " << i + 1 << " 0 R\n"
<< ">>\n";
EndObj();
}
int outlines = BeginObj();
out << "<< /Type /Outlines\n"
"/Count 0\n"
">>\n";
EndObj();
int catalog = BeginObj();
out << "<< /Type /Catalog\n"
<< "/Outlines " << outlines << " 0 R\n"
<< "/Pages " << pages << " 0 R\n"
<< ">>\n";
EndObj();
int startxref = out.GetCount();
out << "xref\n"
<< "0 " << offset.GetCount() + 1 << "\n";
out << "0000000000 65535 f\r\n";
for(int i = 0; i < offset.GetCount(); i++)
out << Sprintf("%010d 00000 n\r\n", offset[i]);
out << "\n"
<< "trailer\n"
<< "<< /Size " << offset.GetCount() + 1 << "\n"
<< "/Root " << catalog << " 0 R\n"
<< ">>\n"
<< "startxref\r\n"
<< startxref << "\r\n"
<< "%%EOF\r\n";
return out;
}
END_UPP_NAMESPACE

343
uppsrc/PdfDraw/PdfDraw.h Normal file
View file

@ -0,0 +1,343 @@
#ifndef _PDF_pdf_h_
#define _PDF_pdf_h_
#include <Draw/Draw.h>
#include <plugin/z/z.h>
NAMESPACE_UPP
class TTFReader {
struct TTFStream {
struct Fail {};
virtual void Raw(void *ptr, int count) = 0;
TTFStream& operator%(byte& q);
TTFStream& operator%(int32& q);
TTFStream& operator%(uint32& q);
TTFStream& operator%(int16& q);
TTFStream& operator%(uint16& q);
virtual ~TTFStream() {}
};
struct TTFStreamIn : TTFStream {
const char *beg;
const char *s;
const char *lim;
virtual void Raw(void *ptr, int count);
void Seek(int offset);
int Get8();
int Get16();
int Get32();
String Get(int n);
virtual ~TTFStreamIn() {}
};
struct TTFStreamOut : TTFStream {
String out;
virtual void Raw(void *ptr, int count) { out.Cat((const char *)ptr, count); }
void Put8(int data) { out.Cat(data); }
void Put16(int data) { Put8(HIBYTE(data)); Put8(LOBYTE(data)); }
void Put32(int data) { Put16(HIWORD(data)); Put16(LOWORD(data)); }
void Put(const String& s) { out.Cat(s); }
operator String() const { return out; }
virtual ~TTFStreamOut() {}
};
String font;
struct Table : Moveable<Table> {
int offset;
int length;
};
VectorMap<String, Table> table;
word zero[256];
word *cmap[256];
struct GlyphInfo : Moveable<GlyphInfo> {
int offset;
int size;
uint16 advanceWidth;
int16 leftSideBearing;
};
Vector<GlyphInfo> glyphinfo;
void SetGlyph(wchar ch, word glyph);
struct Fail {};
static void Error() { throw Fail(); }
int Peek8(const char *s);
int Peek16(const char *s);
int Peek32(const char *s);
int Peek8(const char *s, int i);
int Peek16(const char *s, int i);
int Peek32(const char *s, int i);
int Read8(const char *&s);
int Read16(const char *&s);
int Read32(const char *&s);
String Read(const char *&s, int n);
void Free();
void Reset();
const char *Seek(const char *tab, int& len);
const char *Seek(const char *tab);
void Seek(const char *tab, TTFStreamIn& s);
String GetTable(const char *tab);
enum {
ARG_1_AND_2_ARE_WORDS = (1<<0),
ARGS_ARE_XY_VALUES = (1<<1),
ROUND_XY_TO_GRID = (1<<2),
WE_HAVE_A_SCALE = (1<<3),
MORE_COMPONENTS = (1<<5),
WE_HAVE_AN_X_AND_Y_SCALE = (1<<6),
WE_HAVE_A_TWO_BY_TWO = (1<<7),
WE_HAVE_INSTRUCTIONS = (1<<8),
USE_MY_METRICS = (1<<9),
};
struct NewTable {
String name;
String data;
dword checksum;
};
static void Add(Array<NewTable>& t, const char *name, const String& data);
static void Set(NewTable& m, const String& data);
static String CreateHeader(const Array<NewTable>& t);
static inline int Copy8(TTFStreamOut& out, TTFStreamIn& in)
{ int q = in.Get8(); out.Put8(q); return q; }
static inline int Copy16(TTFStreamOut& out, TTFStreamIn& in)
{ int q = in.Get16(); out.Put16(q); return q; }
static inline int Copy32(TTFStreamOut& out, TTFStreamIn& in)
{ int q = in.Get32(); out.Put32(q); return q; }
static inline String Copy(TTFStreamOut& out, TTFStreamIn& in, int n)
{ String q = in.Get(n); out.Put(q); return q; }
public:
struct Head {
dword version;
dword fontRevision;
uint32 checkSumAdjustment;
uint32 magicNumber;
uint16 flags;
uint16 unitsPerEm;
byte created[8];
byte modified[8];
int16 xMin;
int16 yMin;
int16 xMax;
int16 yMax;
uint16 macStyle;
uint16 lowestRecPPEM;
int16 fontDirectionHint;
int16 indexToLocFormat;
int16 glyphDataFormat;
void Serialize(TTFStream& s);
};
struct Hhea {
uint32 version;
int16 ascent;
int16 descent;
int16 lineGap;
uint16 advanceWidthMax;
int16 minLeftSideBearing;
int16 minRightSideBearing;
int16 xMaxExtent;
int16 caretSlopeRise;
int16 caretSlopeRun;
int16 caretOffset;
int16 reserved1;
int16 reserved2;
int16 reserved3;
int16 reserved4;
int16 metricDataFormat;
uint16 numOfLongHorMetrics;
void Serialize(TTFStream& s);
};
struct Maxp {
uint32 version;
uint16 numGlyphs;
uint16 maxPoints;
uint16 maxContours;
uint16 maxComponentPoints;
uint16 maxComponentContours;
uint16 maxZones;
uint16 maxTwilightPoints;
uint16 maxStorage;
uint16 maxFunctionDefs;
uint16 maxInstructionDefs;
uint16 maxStackElements;
uint16 maxSizeOfInstructions;
uint16 maxComponentElements;
uint16 maxComponentDepth;
void Serialize(TTFStream& s);
};
struct Post {
uint32 format;
int32 italicAngle;
int16 underlinePosition;
int16 underlineThickness;
uint16 isFixedPitch;
uint16 reserved;
uint32 minMemType42;
uint32 maxMemType42;
uint32 minMemType1;
uint32 maxMemType1;
void Serialize(TTFStream& s);
};
Head head;
Hhea hhea;
Maxp maxp;
Post post;
String ps_name;
int GetGlyph(wchar chr) { return cmap[HIBYTE(chr)][LOBYTE(chr)]; }
word GetAdvanceWidth(wchar chr) { return glyphinfo[GetGlyph(chr)].advanceWidth; }
String Subset(const Vector<wchar>& chars, int first = 0, bool os2 = false);
bool Open(const String& fnt, bool symbol = false, bool justcheck = false);
TTFReader();
~TTFReader();
};
class PdfDraw : public Draw {
public:
virtual dword GetInfo() const;
virtual Size GetPageSize() const;
virtual void StartPage();
virtual void EndPage();
virtual void BeginOp();
virtual void EndOp();
virtual void OffsetOp(Point p);
virtual bool ClipOp(const Rect& r);
virtual bool ClipoffOp(const Rect& r);
virtual bool ExcludeClipOp(const Rect& r);
virtual bool IntersectClipOp(const Rect& r);
virtual bool IsPaintingOp(const Rect& r) const;
virtual void DrawRectOp(int x, int y, int cx, int cy, Color color);
virtual void DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color);
virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color);
virtual void DrawPolyPolylineOp(const Point *vertices, int vertex_count,
const int *counts, int count_count,
int width, Color color, Color doxor);
virtual void DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count,
const int *subpolygon_counts, int scc,
const int *disjunct_polygon_counts, int dpcc,
Color color, int width, Color outline,
uint64 pattern, Color doxor);
virtual void DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor);
virtual void DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color);
virtual void DrawTextOp(int x, int y, int angle, const wchar *text, Font font,
Color ink, int n, const int *dx);
private:
struct CharPos : Moveable<CharPos> { word fi, ci; };
struct OutlineInfo : Moveable<OutlineInfo> {
bool ttf;
bool sitalic;
};
VectorMap<Font, OutlineInfo> outline_info;
VectorMap<Font, Vector<wchar> > pdffont;
VectorMap<Font, VectorMap<wchar, CharPos> > fontchars;
Vector<Image> image;
Vector<Rect> imagerect;
Vector<int> offset;
String out;
String page;
Size pgsz;
Color rgcolor;
Color RGcolor;
int fontid;
double textht;
double linewidth;
int margin;
inline double Pt(double dot) { return 0.12 * dot; }
int Pos() { return offset.GetCount() + 1; }
int BeginObj();
void EndObj();
int PutStream(const String& data, const String& keys = Null);
void PutRect(const Rect& rc);
void PutrgColor(Color rg);
void PutRGColor(Color RG);
void PutFontHeight(int fi, double ht);
void PutLineWidth(int lw);
CharPos GetCharPos(Font fnt, wchar chr);
void FlushText(int dx, int fi, int height, const String& txt);
static String PdfColor(Color c);
OutlineInfo GetOutlineInfo(Font fnt);
struct M22 {
double a, b, c, d;
void Mul(double a1, double b1, double c1, double d1) {
M22 t;
t.a = a * a1 + b * c1;
t.b = a * b1 + b * d1;
t.c = c * a1 + d * c1;
t.d = c * b1 + d * d1;
*this = t;
}
M22(double a, double b, double c, double d) : a(a), b(b), c(c), d(d) {}
M22() : a(1), b(0), c(0), d(1) {}
};
void Init(int pagecx, int pagecy, int margin);
struct RGlyph : Moveable<RGlyph> {
String data;
Size sz;
int x;
};
RGlyph RasterGlyph(Font fnt, int chr);
public:
String Finish();
void Clear();
PdfDraw(int pagecx, int pagecy) { Init(pagecx, pagecy, 0); }
PdfDraw(Size pgsz = Size(5100, 6600)) { Init(pgsz.cx, pgsz.cy, 0); }
};
String Pdf(const Array<Drawing>& report, Size pagesize, int margin);
END_UPP_NAMESPACE
#endif

View file

@ -0,0 +1,16 @@
description "PDF output as Draw derived class\377128,0,255";
uses
Draw;
file
PdfDraw.h,
TTFStream.cpp,
TTFStruct.cpp,
TTFReader.cpp,
TTFSubset.cpp,
PdfDraw.cpp,
PdfReport.icpp,
Info readonly separator,
Copying;

View file

@ -0,0 +1,21 @@
#include "PdfDraw.h"
NAMESPACE_UPP
String Pdf(const Array<Drawing>& report, Size sz, int margin)
{
PdfDraw w(sz + 2 * margin);
for(int i = 0; i < report.GetCount(); i++) {
w.StartPage();
w.DrawDrawing(margin, margin, sz.cx, sz.cy, report[i]);
w.EndPage();
}
return w.Finish();
}
INITBLOCK
{
SetDrawingToPdfFn(Pdf);
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,311 @@
#include "PdfDraw.h"
NAMESPACE_UPP
#define LLOG(x) // LOG(x)
#define LDUMP(x) // LLOG(#x << " = " << x);
int TTFReader::Peek8(const char *s)
{
if(s + 1 > font.End())
Error();
return (byte)*s;
}
int TTFReader::Peek16(const char *s)
{
if(s + 2 > font.End())
Error();
return ((byte)s[0] << 8) | (byte)s[1];
}
int TTFReader::Peek32(const char *s)
{
if(s + 4 > font.End())
Error();
return ((byte)s[0] << 24) | ((byte)s[1] << 16) | ((byte)s[2] << 8) | (byte)s[3];
}
int TTFReader::Peek8(const char *s, int i)
{
return Peek16(s + i);
}
int TTFReader::Peek16(const char *s, int i)
{
return Peek16(s + 2 * i);
}
int TTFReader::Peek32(const char *s, int i)
{
return Peek32(s + 4 * i);
}
int TTFReader::Read8(const char *&s)
{
int q = byte(*s); s++; return q;
}
int TTFReader::Read16(const char *&s)
{
int q = Peek16(s); s += 2; return q;
}
int TTFReader::Read32(const char *&s)
{
int q = Peek32(s); s += 4; return q;
}
String TTFReader::Read(const char *&s, int n)
{
if(s + n > font.End())
Error();
String q(s, n);
s += n;
return q;
}
void TTFReader::Reset()
{
memset(zero, 0, sizeof(zero));
for(int i = 0; i < 256; i++)
cmap[i] = zero;
}
void TTFReader::Free()
{
for(int i = 0; i < 256; i++)
if(cmap[i] != zero)
delete[] cmap[i];
}
void TTFReader::SetGlyph(wchar chr, word glyph)
{
int h = HIBYTE(chr);
if(cmap[h] == zero)
memset(cmap[h] = new word[256], 0, 256 * sizeof(word));
cmap[h][LOBYTE(chr)] = glyph;
}
const char *TTFReader::Seek(const char *tab, int& len)
{
ASSERT(strlen(tab) == 4);
int q = table.Find(tab);
if(q < 0)
Error();
len = table[q].length;
return ~font + table[q].offset;
}
const char *TTFReader::Seek(const char *tab)
{
int dummy;
return Seek(tab, dummy);
}
void TTFReader::Seek(const char *tab, TTFStreamIn& s)
{
int len;
s.beg = s.s = Seek(tab, len);
s.lim = s.s + len;
}
String TTFReader::GetTable(const char *tab)
{
ASSERT(strlen(tab) == 4);
int q = table.Find(tab);
if(q < 0)
return Null;
return String(~font + table[q].offset, table[q].length);
}
bool TTFReader::Open(const String& fnt, bool symbol, bool justcheck)
{
try {
int i;
Free();
Reset();
table.Clear();
glyphinfo.Clear();
font = fnt;
const char *s = fnt;
int q = Read32(s);
if(q != 0x74727565 && q != 0x00010000)
Error();
int n = Read16(s);
s += 6;
while(n--) {
Table& t = table.Add(Read(s, 4));
s += 4;
t.offset = Read32(s);
t.length = Read32(s);
}
for(i = 0; i < table.GetCount(); i++)
LLOG("table: " << table.GetKey(i) << " offset: " << table[i].offset << " length: " << table[i].length);
TTFStreamIn is;
Seek("head", is);
head.Serialize(is);
if(head.magicNumber != 0x5F0F3CF5)
Error();
LDUMP(head.unitsPerEm);
LDUMP(head.xMin);
LDUMP(head.yMin);
LDUMP(head.xMax);
LDUMP(head.yMax);
LDUMP(head.indexToLocFormat);
Seek("maxp", is);
maxp.Serialize(is);
LDUMP(maxp.numGlyphs);
Seek("post", is);
post.Serialize(is);
// LLOGHEXLDUMP(is.s, is.lim - is.s);
LDUMP((post.format >> 16));
LDUMP(post.italicAngle);
LDUMP(post.italicAngle);
LDUMP(post.underlinePosition);
LDUMP(post.underlineThickness);
LDUMP(post.italicAngle);
if(justcheck)
return true;
Seek("hhea", is);
hhea.Serialize(is);
LDUMP(hhea.ascent);
LDUMP(hhea.descent);
LDUMP(hhea.lineGap);
LDUMP(hhea.advanceWidthMax);
LDUMP(hhea.numOfLongHorMetrics);
if(hhea.numOfLongHorMetrics > maxp.numGlyphs)
Error();
glyphinfo.SetCount(maxp.numGlyphs);
s = Seek("hmtx");
int aw = 0;
for(i = 0; i < hhea.numOfLongHorMetrics; i++) {
aw = glyphinfo[i].advanceWidth = (uint16)Read16(s);
glyphinfo[i].leftSideBearing = (int16)Read16(s);
}
for(; i < maxp.numGlyphs; i++) {
glyphinfo[i].advanceWidth = aw;
glyphinfo[i].leftSideBearing = (int16)Read16(s);
}
s = Seek("loca");
for(i = 0; i < maxp.numGlyphs; i++)
if(head.indexToLocFormat) {
glyphinfo[i].offset = Peek32(s, i);
glyphinfo[i].size = Peek32(s, i + 1) - glyphinfo[i].offset;
}
else {
glyphinfo[i].offset = 2 * (word)Peek16(s, i);
glyphinfo[i].size = 2 * (word)Peek16(s, i + 1) - glyphinfo[i].offset;
}
for(i = 0; i < maxp.numGlyphs; i++)
LLOG(i << " advance: " << glyphinfo[i].advanceWidth << ", left: " << glyphinfo[i].leftSideBearing
<< ", offset: " << glyphinfo[i].offset << ", size: " << glyphinfo[i].size);
s = Seek("cmap");
const char *p = s;
p += 2;
n = Read16(p);
while(n--) {
int pid = Read16(p);
int psid = Read16(p);
int offset = Read32(p);
LLOG("cmap pid: " << pid << " psid: " << psid << " format: " << Peek16(s + offset));
//Test with Symbol font !!!; improve - Unicode first, 256 bytes later..., symbol...
if(symbol) {
if(pid == 1 && psid == 0 && Peek16(s + offset) == 0) {
LLOG("Reading symbol table");
p = s + offset + 6;
for(int i = 0; i < 256; i++)
SetGlyph(i, (byte)p[i]);
break;
}
}
else
if(pid == 3 && psid == 1) {
p = s + offset;
n = Peek16(p + 6) >> 1;
LLOG("Found UNICODE encoding, offset " << offset << ", segments " << n);
const char *seg_end = p + 14;
const char *seg_start = seg_end + 2 * n + 2;
const char *idDelta = seg_start + 2 * n;
const char *idRangeOffset = idDelta + 2 * n;
for(int i = 0; i < n; i++) {
int start = Peek16(seg_start, i);
int end = Peek16(seg_end, i);
int delta = Peek16(idDelta, i);
int ro = Peek16(idRangeOffset, i);
if (ro && delta == 0) {
LLOG("RangeOffset start: " << start << ", end: " << end << ", delta: " << (int16)delta);
LLOG("ro " << ro);
const char *q = idRangeOffset + 2 * i + ro;
for(int c = start; c <= end; c++) {
SetGlyph(c, (word)Read16(q));
}
}
else {
LLOG("start: " << start << ", end: " << end << ", delta: " << (int16)delta);
for(int c = start; c <= end; c++)
SetGlyph(c, c + delta);
}
}
break;
}
}
const char *strings = Seek("name");
s = strings + 2;
int count = Read16(s);
strings += (word)Read16(s);
for(int i = 0; i < count; i++) {
int platform = Read16(s);
s += 4;
if(Read16(s) == 6) {
int len = Read16(s);
int offset = Read16(s);
if(platform == 1)
ps_name = String(strings + offset, len);
else {
s = strings + offset;
len >>= 1;
while(len--)
ps_name.Cat(Read16(s));
}
break;
}
s += 4;
}
LDUMP(ps_name);
}
catch(Fail) {
return false;
}
catch(TTFStream::Fail) {
return false;
}
return true;
}
TTFReader::TTFReader()
{
Reset();
}
TTFReader::~TTFReader()
{
Free();
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,110 @@
#include "PdfDraw.h"
NAMESPACE_UPP
TTFReader::TTFStream& TTFReader::TTFStream::operator%(byte& q) {
Raw(&q, 1);
return *this;
}
#ifdef CPU_LE
TTFReader::TTFStream& TTFReader::TTFStream::operator%(int32& q) {
byte *h = (byte *)&q;
*this % h[3] % h[2] % h[1] % h[0];
return *this;
}
TTFReader::TTFStream& TTFReader::TTFStream::operator%(uint32& q) {
byte *h = (byte *)&q;
*this % h[3] % h[2] % h[1] % h[0];
return *this;
}
TTFReader::TTFStream& TTFReader::TTFStream::operator%(int16& q) {
byte *h = (byte *)&q;
*this % h[1] % h[0];
return *this;
}
TTFReader::TTFStream& TTFReader::TTFStream::operator%(uint16& q) {
byte *h = (byte *)&q;
*this % h[1] % h[0];
return *this;
}
#else
TTFReader::TTFStream& TTFReader::TTFStream::operator%(int32& q) {
byte *h = (byte *)&q;
*this % h[0] % h[1] % h[2] % h[3];
return *this;
}
TTFReader::TTFStream& TTFReader::TTFStream::operator%(uint32& q) {
byte *h = (byte *)&q;
*this % h[0] % h[1] % h[2] % h[3];
return *this;
}
TTFReader::TTFStream& TTFReader::TTFStream::operator%(int16& q) {
byte *h = (byte *)&q;
*this % h[0] % h[1];
return *this;
}
TTFReader::TTFStream& TTFReader::TTFStream::operator%(uint16& q) {
byte *h = (byte *)&q;
*this % h[0] % h[1];
return *this;
}
#endif
void TTFReader::TTFStreamIn::Seek(int offset)
{
ASSERT(offset >= 0 && offset < lim - beg);
s = beg + offset;
}
int TTFReader::TTFStreamIn::Get8()
{
if(s + 1 > lim)
throw Fail();
int q = (byte)*s;
s++;
return q;
}
int TTFReader::TTFStreamIn::Get16()
{
if(s + 2 > lim)
throw Fail();
int q = ((byte)s[0] << 8) | (byte)s[1];
s += 2;
return q;
}
int TTFReader::TTFStreamIn::Get32()
{
if(s + 4 > lim)
throw Fail();
int q = ((byte)s[0] << 24) | ((byte)s[1] << 16) | ((byte)s[2] << 8) | (byte)s[3];
s += 2;
return q;
}
String TTFReader::TTFStreamIn::Get(int n)
{
if(s + n > lim)
throw Fail();
String r(s, n);
s += n;
return r;
}
void TTFReader::TTFStreamIn::Raw(void *ptr, int count) {
if(s + count > lim)
throw Fail();
memcpy(ptr, s, count);
s += count;
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,37 @@
#include "PdfDraw.h"
NAMESPACE_UPP
void TTFReader::Head::Serialize(TTFStream& s)
{
s % version % fontRevision % checkSumAdjustment % magicNumber % flags % unitsPerEm;
s.Raw(created, 8);
s.Raw(modified, 8);
s % xMin % yMin % xMax % yMax % macStyle % lowestRecPPEM % fontDirectionHint
% indexToLocFormat % glyphDataFormat;
}
void TTFReader::Hhea::Serialize(TTFStream& s)
{
reserved1 = reserved2 = reserved3 = reserved4 = 0;
s % version % ascent % descent % lineGap % advanceWidthMax % minLeftSideBearing
% minRightSideBearing % xMaxExtent % caretSlopeRise % caretSlopeRun % caretOffset
% reserved1 % reserved2 % reserved3 % reserved4 % metricDataFormat % numOfLongHorMetrics;
}
void TTFReader::Maxp::Serialize(TTFStream& s)
{
s % version % numGlyphs % maxPoints % maxContours % maxComponentPoints
% maxComponentContours % maxZones % maxTwilightPoints % maxStorage
% maxFunctionDefs % maxInstructionDefs % maxStackElements
% maxSizeOfInstructions % maxComponentElements % maxComponentDepth;
}
void TTFReader::Post::Serialize(TTFStream& s)
{
reserved = 0;
s % format % italicAngle % underlinePosition % underlineThickness % isFixedPitch
% reserved % minMemType42 % maxMemType42 % minMemType1 % maxMemType1;
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,207 @@
#include "PdfDraw.h"
NAMESPACE_UPP
dword sCheckSum(const String& data)
{
const byte *s = (byte *)~data;
const byte *lim = s + (data.GetCount() & ~3);
dword sum = 0;
while(s < lim) {
sum += (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
s += 4;
}
byte h[4];
h[0] = h[1] = h[2] = h[3] = 0;
byte *t = h;
while(s < (byte *)data.End())
*t++ = *s++;
sum += (h[0] << 24) | (h[1] << 16) | (h[2] << 8) | h[3];
return sum;
}
void TTFReader::Set(NewTable& m, const String& data)
{
m.data = data;
m.checksum = sCheckSum(data);
}
void TTFReader::Add(Array<NewTable>& t, const char *name, const String& data)
{
if(IsNull(data))
return;
NewTable& m = t.Add();
m.name = name;
ASSERT(m.name.GetCount() == 4);
Set(m, data);
m.checksum = sCheckSum(m.data);
}
String TTFReader::CreateHeader(const Array<NewTable>& t)
{
TTFStreamOut out;
int i = 1;
int k = 0;
while(i <= t.GetCount()) {
i <<= 1;
k++;
}
out.Put32(0x00010000);
out.Put16(t.GetCount());
out.Put16(i << 3);
out.Put16(k - 1);
out.Put16((t.GetCount() << 4) - (i << 3));
int offset = 16 * t.GetCount() + 12;
for(int i = 0; i < t.GetCount(); i++) {
const NewTable& m = t[i];
out.Put(m.name);
out.Put32(m.checksum);
out.Put32(offset);
out.Put32(m.data.GetLength());
offset += (m.data.GetLength() + 3) & ~3;
}
return out;
}
String TTFReader::Subset(const Vector<wchar>& chars, int first, bool os2)
{
try {
ASSERT(chars.GetCount() + first < 256);
TTFStreamOut cmap;
cmap.Put16(0);
cmap.Put16(1);
cmap.Put16(1);
cmap.Put16(0);
cmap.Put32(cmap.out.GetLength() + 4);
cmap.Put16(0);
cmap.Put16(262);
cmap.Put16(0);
Index<int> glyph;
glyph.Add(0);
for(int i = 0; i < first; i++)
cmap.Put8(0);
for(int i = 0; i < chars.GetCount(); i++) {
int q = GetGlyph(chars[i]);
if(q) {
cmap.Put8(glyph.GetCount());
glyph.Add(q);
}
else
cmap.Put8(0);
}
for(int i = chars.GetCount(); i < 256; i++)
cmap.Put8(0);
TTFStreamOut loca;
TTFStreamIn in;
TTFStreamOut glyf;
TTFStreamOut hmtx;
Seek("glyf", in);
for(int i = 0; i < glyph.GetCount(); i++) {
int gi = glyph[i];
if(gi >= glyphinfo.GetCount())
throw Fail();
const GlyphInfo &gf = glyphinfo[gi];
loca.Put32(glyf.out.GetLength());
hmtx.Put16(gf.advanceWidth);
hmtx.Put16(gf.leftSideBearing);
if(gf.size) {
if(gf.size < 10)
Error();
in.Seek(gf.offset);
int c = (int16)Copy16(glyf, in);
Copy(glyf, in, 8);
if(c < 0) {
int flags;
do {
flags = Copy16(glyf, in);
glyf.Put16(glyph.FindAdd(in.Get16()));
if(flags & ARG_1_AND_2_ARE_WORDS)
Copy(glyf, in, 4);
else
Copy(glyf, in, 2);
if(flags & WE_HAVE_A_SCALE)
Copy16(glyf, in);
else
if(flags & WE_HAVE_AN_X_AND_Y_SCALE)
Copy(glyf, in, 4);
else
if(flags & WE_HAVE_A_TWO_BY_TWO)
Copy(glyf, in, 8);
}
while(flags & MORE_COMPONENTS);
if(flags & WE_HAVE_INSTRUCTIONS)
Copy(glyf, in, Copy16(glyf, in));
}
else
Copy(glyf, in, gf.size - 10);
}
}
loca.Put32(glyf.out.GetLength());
Hhea nhhea = hhea;
nhhea.numOfLongHorMetrics = glyph.GetCount();
TTFStreamOut hhea;
nhhea.Serialize(hhea);
Maxp nmaxp = maxp;
nmaxp.numGlyphs = glyph.GetCount();
TTFStreamOut maxp;
nmaxp.Serialize(maxp);
Post npost = post;
npost.format = 0x00030000;
TTFStreamOut post;
npost.Serialize(post);
Head nhead = head;
nhead.checkSumAdjustment = 0;
nhead.indexToLocFormat = 1;
TTFStreamOut head;
nhead.Serialize(head);
Array<NewTable> tab;
if(os2)
Add(tab, "OS/2", GetTable("OS/2"));
Add(tab, "cmap", cmap);
Add(tab, "cvt ", GetTable("cvt "));
Add(tab, "fpgm", GetTable("fpgm"));
Add(tab, "glyf", glyf);
int headi = tab.GetCount();
Add(tab, "head", head);
Add(tab, "hhea", hhea);
Add(tab, "hmtx", hmtx);
Add(tab, "loca", loca);
Add(tab, "maxp", maxp);
Add(tab, "name", GetTable("name"));
Add(tab, "post", post);
Add(tab, "prep", GetTable("prep"));
dword chksum = sCheckSum(CreateHeader(tab));
for(int i = 0; i < tab.GetCount(); i++)
chksum += tab[i].checksum;
nhead.checkSumAdjustment = 0xB1B0AFBA - chksum;
head.out.Clear();
nhead.Serialize(head);
Set(tab[headi], head);
String result = CreateHeader(tab);
for(int i = 0; i < tab.GetCount(); i++) {
result.Cat(tab[i].data);
result.Cat(0, (4 - result.GetCount()) & 3);
}
return result;
}
catch(Fail) {
return String::GetVoid();
}
catch(TTFStream::Fail) {
return String::GetVoid();
}
}
END_UPP_NAMESPACE

7
uppsrc/PdfDraw/init Normal file
View file

@ -0,0 +1,7 @@
#ifndef _PdfDraw_icpp_init_stub
#define _PdfDraw_icpp_init_stub
#include "Draw/init"
#define BLITZ_INDEX__ F2EB858D15FF91342F7F9648AA934C9C8
#include "PdfReport.icpp"
#undef BLITZ_INDEX__
#endif

6
uppsrc/PdfDraw/ttf.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef _PDF_ttf_h_
#define _PDF_ttf_h_
#endif