diff --git a/uppsrc/Draw/Draw.h b/uppsrc/Draw/Draw.h index c5b029ce1..3436095b6 100644 --- a/uppsrc/Draw/Draw.h +++ b/uppsrc/Draw/Draw.h @@ -885,6 +885,7 @@ DrawingToPdfFnType GetDrawingToPdfFn(); #include "Display.h" #include "Cham.h" #include "DDARasterizer.h" +#include "SDraw.h" END_UPP_NAMESPACE diff --git a/uppsrc/Draw/Draw.upp b/uppsrc/Draw/Draw.upp index db2a68952..fd24824d6 100644 --- a/uppsrc/Draw/Draw.upp +++ b/uppsrc/Draw/Draw.upp @@ -61,6 +61,12 @@ file DDA readonly separator, DDARasterizer.h, DDARasterizer.cpp, + SDraw readonly separator, + SDraw.h, + SDrawClip.cpp, + SDrawPut.cpp, + SDrawText.cpp, + SDraw.cpp, Chameleon readonly separator, Cham.h, Cham.cpp, diff --git a/uppsrc/Draw/ImageOp.cpp b/uppsrc/Draw/ImageOp.cpp index 7ba5bad47..22c7c634b 100644 --- a/uppsrc/Draw/ImageOp.cpp +++ b/uppsrc/Draw/ImageOp.cpp @@ -122,6 +122,37 @@ Image Crop(const Image& img, int x, int y, int cx, int cy) return Crop(img, RectC(x, y, cx, cy)); } +bool IsUniform(const RGBA *s, RGBA c, int add, int n) +{ + while(n-- > 0) { + if(*s != c) + return false; + s += add; + } + return true; +} + +Image AutoCrop(const Image& m, RGBA c) +{ + Size isz = m.GetSize(); + Rect r = isz; + for(r.top = 0; r.top < isz.cy && IsUniform(m[r.top], c, 1, isz.cx); r.top++) + ; + for(r.bottom = isz.cy; r.bottom > r.top && IsUniform(m[r.bottom - 1], c, 1, isz.cx); r.bottom--) + ; + if(r.bottom <= r.top) + return Null; + int h = r.GetHeight(); + const RGBA *p = m[r.top]; + for(r.left = 0; r.left < isz.cy && IsUniform(p + r.left, c, isz.cx, h); r.left++) + ; + for(r.right = isz.cx; r.right > r.left && IsUniform(p + r.right - 1, c, isz.cx, h); r.right--) + ; + Point p1 = m.GetHotSpot() - r.TopLeft(); + Point p2 = m.Get2ndSpot() - r.TopLeft(); + return WithHotSpots(Crop(m, r), p1.x, p1.y, p2.x, p2.y); +} + Image ColorMask(const Image& src, Color key) { ImageBuffer ib(src.GetSize()); diff --git a/uppsrc/Draw/ImageOp.h b/uppsrc/Draw/ImageOp.h index 713ee586b..ba3be87cd 100644 --- a/uppsrc/Draw/ImageOp.h +++ b/uppsrc/Draw/ImageOp.h @@ -18,6 +18,8 @@ void Crop(RasterEncoder& tgt, Raster& img, const Rect& rc); Image Crop(const Image& img, const Rect& rc); Image Crop(const Image& img, int x, int y, int cx, int cy); +Image AutoCrop(const Image& m, RGBA c); + Image ColorMask(const Image& src, Color transparent); void CanvasSize(RasterEncoder& tgt, Raster& img, int cx, int cy); diff --git a/uppsrc/Draw/SDraw.cpp b/uppsrc/Draw/SDraw.cpp new file mode 100644 index 000000000..e12eb2b9a --- /dev/null +++ b/uppsrc/Draw/SDraw.cpp @@ -0,0 +1,38 @@ +#include "Draw.h" + +NAMESPACE_UPP + +dword SDraw::GetInfo() const +{ + return DRAWTEXTLINES; +} + +void SDraw::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color) +{ + // TODO +} + +void SDraw::DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor) +{ + // TODO +} + +void SDraw::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color) +{ + Width(width); + docolor = color; + Move(Point(x1, y1)); + Line(Point(x2, y2)); +} + +void SDraw::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) +{ + // TODO +} + +void SDraw::DrawPolyPolylineOp(const Point *vertices, int vertex_count, const int *counts, int count_count, int width, Color color, Color doxor) +{ + // TODO +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Draw/SDraw.h b/uppsrc/Draw/SDraw.h new file mode 100644 index 000000000..4811e6284 --- /dev/null +++ b/uppsrc/Draw/SDraw.h @@ -0,0 +1,46 @@ +struct SDraw : Draw, DDARasterizer { + virtual dword GetInfo() const; + + virtual void BeginOp(); + virtual bool ClipOp(const Rect& r); + virtual bool ClipoffOp(const Rect& r); + virtual bool IntersectClipOp(const Rect& r); + virtual void OffsetOp(Point p); + virtual bool ExcludeClipOp(const Rect& r); + virtual void EndOp(); + virtual bool IsPaintingOp(const Rect& r) const; + + virtual void SysDrawImageOp(int x, int y, const Image& img, Color color); + virtual void SysDrawImageOp(int x, int y, const Image& img, const Rect& src, Color color); + virtual void DrawRectOp(int x, int y, int cx, int cy, Color color); + + virtual void DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx); + + virtual void DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color); + virtual void DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor); + virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color); + 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 DrawPolyPolylineOp(const Point *vertices, int vertex_count, const int *counts, int count_count, int width, Color color, Color doxor); + + virtual void PutHorz(int x, int y, int cx); + virtual void PutVert(int x, int y, int cy); + +private: + struct Cloff { + Vector clip; + Point offset; + + void operator<<=(const Cloff& b) { clip <<= b.clip; offset = b.offset; } + }; + + Array cloff; + + Color docolor; + +public: + virtual void PutImage(Point p, const Image& m, const Rect& src) = 0; + virtual void PutRect(const Rect& r, Color color) = 0; + virtual Image RenderGlyph(Point at, int angle, int chr, Font fnt, Color color, Size sz) = 0; + + void Init(const Rect& r); +}; diff --git a/uppsrc/Draw/SDrawClip.cpp b/uppsrc/Draw/SDrawClip.cpp new file mode 100644 index 000000000..bb72dbdb4 --- /dev/null +++ b/uppsrc/Draw/SDrawClip.cpp @@ -0,0 +1,69 @@ +#include "Draw.h" + +NAMESPACE_UPP + +void SDraw::Init(const Rect& r) +{ + Cloff& c = cloff.Add(); + c.clip.Add(r); + c.offset = Point(0, 0); +} + +void SDraw::BeginOp() +{ + Cloff& c = cloff.Top(); + cloff.Add() <<= c; +} + +bool SDraw::ClipOp(const Rect& r) +{ + Cloff& c = cloff.Top(); + Cloff& c1 = cloff.Add(); + c1.clip = Intersection(c.clip, r + c.offset); + c1.offset = c.offset; + return c1.clip.GetCount(); +} + +bool SDraw::ClipoffOp(const Rect& r) +{ + Cloff& c = cloff.Top(); + Cloff& c1 = cloff.Add(); + c1.clip = Intersection(c.clip, r + c.offset); + c1.offset = c.offset + r.TopLeft(); + return c1.clip.GetCount(); +} + +bool SDraw::IntersectClipOp(const Rect& r) +{ + Cloff& c = cloff.Top(); + c.clip = Intersection(c.clip, r + c.offset); + return c.clip.GetCount(); +} + +bool SDraw::ExcludeClipOp(const Rect& r) +{ + Cloff& c = cloff.Top(); + bool dummy; + c.clip = Subtract(c.clip, r + c.offset, dummy); + return c.clip.GetCount(); +} + +bool SDraw::IsPaintingOp(const Rect& r) const +{ + return true; +} + +void SDraw::OffsetOp(Point p) +{ + Cloff& c = cloff.Top(); + Cloff& c1 = cloff.Add(); + c1.clip <<= c.clip; + c1.offset = c.offset + p; +} + +void SDraw::EndOp() +{ + cloff.Drop(); +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Draw/SDrawPut.cpp b/uppsrc/Draw/SDrawPut.cpp new file mode 100644 index 000000000..7d7651990 --- /dev/null +++ b/uppsrc/Draw/SDrawPut.cpp @@ -0,0 +1,68 @@ +#include "Draw.h" + +NAMESPACE_UPP + +struct sColorize : public ImageMaker +{ + Image img; + Color color; + + virtual String Key() const { + StringBuffer h; + RawCat(h, color); + RawCat(h, img.GetSerialId()); + return h; + } + + virtual Image Make() const { + return SetColorKeepAlpha(img, color); + } + +}; + +void SDraw::SysDrawImageOp(int x, int y, const Image& img, const Rect& src, Color color) +{ + if(!IsNull(color)) { + sColorize m; + m.img = img; + m.color = color; + SysDrawImageOp(x, y, MakeImage(m), src, Null); + return; + } + Rect sr(Point(x, y) + cloff.Top().offset, (src & img.GetSize()).GetSize()); + const Vector& clip = cloff.Top().clip; + for(int i = 0; i < clip.GetCount(); i++) { + Rect cr = clip[i] & sr; + if(!cr.IsEmpty()) + PutImage(cr.TopLeft(), img, Rect(cr.TopLeft() - sr.TopLeft() + src.TopLeft(), cr.GetSize())); + } +} + +void SDraw::SysDrawImageOp(int x, int y, const Image& img, Color color) +{ + SysDrawImageOp(x, y, img, img.GetSize(), color); +} + +void SDraw::DrawRectOp(int x, int y, int cx, int cy, Color color) +{ + Rect r = RectC(x, y, cx, cy); + r += cloff.Top().offset; + const Vector& clip = cloff.Top().clip; + for(int i = 0; i < clip.GetCount(); i++) { + Rect cr = clip[i] & r; + if(!cr.IsEmpty()) + PutRect(cr, color); + } +} + +void SDraw::PutHorz(int x, int y, int cx) +{ + DrawRect(x, y, cx, 1, docolor); +} + +void SDraw::PutVert(int x, int y, int cy) +{ + DrawRect(x, y, 1, cy, docolor); +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Draw/SDrawText.cpp b/uppsrc/Draw/SDrawText.cpp new file mode 100644 index 000000000..23abe995e --- /dev/null +++ b/uppsrc/Draw/SDrawText.cpp @@ -0,0 +1,60 @@ +#include "Draw.h" + +#define LTIMING(x) RTIMING(x) + +NAMESPACE_UPP + +struct sMakeTextGlyph : public ImageMaker +{ + int chr; + Font font; + int angle; + Color color; + SDraw *draw; + + virtual String Key() const { + StringBuffer h; + RawCat(h, chr); + RawCat(h, font); + RawCat(h, angle); + RawCat(h, color); + return h; + } + + virtual Image Make() const { + LTIMING("Render glyph"); + Point at(font[chr], font.GetLineHeight()); + int n = 2 * (at.x + at.y); + return AutoCrop(WithHotSpot(draw->RenderGlyph(at, angle, chr, font, color, Size(n, n)), at.x, at.y), RGBAZero()); + } +}; + +void SDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx) +{ + sMakeTextGlyph g; + g.font = font; + g.color = ink; + g.angle = angle; + g.draw = this; + for(int i = 0; i < n; i++) { + g.chr = text[i]; + LTIMING("Paint glyph"); + if(font.GetHeight() > 200) { + Point at(font[g.chr], font.GetLineHeight()); + int n = at.x + at.y; + Size bandsz(2 * n, 32); + for(int yy = 0; yy < n; yy += bandsz.cy) { + Image m = RenderGlyph(Point(0, -yy), angle, g.chr, font, ink, bandsz); + SysDrawImageOp(x, y + yy, m, m.GetSize(), Null); + } + } + else { + Image m = MakeImage(g); + Point h = m.GetHotSpot(); + SysDrawImageOp(x - h.x, y - h.y, m, m.GetSize(), Null); + } + x += dx ? *dx++ : font[g.chr]; + } +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Draw/src.tpp/Image$en-us.tpp b/uppsrc/Draw/src.tpp/Image$en-us.tpp index da69c5c22..816e5bff4 100644 --- a/uppsrc/Draw/src.tpp/Image$en-us.tpp +++ b/uppsrc/Draw/src.tpp/Image$en-us.tpp @@ -306,6 +306,12 @@ mage][@(0.0.255) `&]_[*@3 img], [@(0.0.255) const]_[_^Rect^ Rect][@(0.0.255) `&] [%-*@3 y], width [%-*@3 cx] and height [%-*@3 cy].&] [s3;%% &] [s4; &] +[s5;:AutoCrop`(const Image`&`,RGBA`): [_^Image^ Image]_[* AutoCrop]([@(0.0.255) const]_[_^Image^ I +mage][@(0.0.255) `&]_[*@3 m], [_^RGBA^ RGBA]_[*@3 c])&] +[s2;%% Detects rectangular margin with uniform color [%-*@3 c] and +then crops this margin out.&] +[s3;%% &] +[s4; &] [s5;:ColorMask`(const Image`&`,Color`): [_^Image^ Image]_[* ColorMask]([@(0.0.255) const]_[_^Image^ I mage][@(0.0.255) `&]_[*@3 src], [_^Color^ Color]_[*@3 transparent])&] [s2;%% Returns a new Image based on [%-*@3 src] replaced Color [%-*@3 transparent]