Q: I need to read a PDF file containing relatively simple vector
shapes and to convert the vector shapes into a .NET GraphicsPath. The
GraphicsPath will later be used to draw the shapes. Even though your
SDK may provide the ability to render/rasterize a PDF, I need to
manipulate the data in vector format (GraphicsPath).
Does PDFNet SDK provide this functionality?
------
A: Using PDFNet SDK (http://www.pdftron.com/net) you can extract
vector data and other content from PDF documents. As an example of how
this can be implemented, please take a look at ProcessPath function in
ElementReaderAdv sample project: http://www.pdftron.com/net/samplecode.html#ElementReaderAdv.
A function used to extract a PDF path as a .NET GraphicsPath may look
as follows:
static public GraphicsPath GetGraphicsPath(ElementReader reader,
Element element)
{
if (element.GetType() != Element.Type.e_path) return null;
GraphicsPath gdi_path = new GraphicsPath();
if (element.IsClippingPath())
{
// gdi_path.FillMode = element.IsClipWindingFill() ?
FillMode.Winding : FillMode.Alternate);
}
double[] data = element.GetPathPoints();
int data_sz = element.GetPointCount();
byte[] opr = element.GetPathTypes();
int opr_sz = element.GetPathTypesCount();
int opr_itr = 0, opr_end = opr_sz;
int data_itr = 0, data_end = data_sz;
double x1, y1, x2, y2, x3, y3;
double start_x = 0, start_y = 0, last_x = 0, last_y = 0;
// Use element.GetCTM() if you are interested in CTM (current
transformation matrix).
// This transform can be applied to graphics object when drawing the
element
// e.g. using graphics.MultiplyTransform(mtx, MatrixOrder.Prepend)
etc.
for (; opr_itr < opr_end; ++opr_itr)
{
switch ((Element.PathSegmentType)((int)opr[opr_itr]))
{
case Element.PathSegmentType.e_moveto:
start_x = last_x = data[data_itr]; ++data_itr;
start_y = last_y = data[data_itr]; ++data_itr;
gdi_path.StartFigure();
break;
case Element.PathSegmentType.e_lineto:
x1 = data[data_itr]; ++data_itr;
y1 = data[data_itr]; ++data_itr;
gdi_path.AddLine((float)last_x, (float)last_y,
(float)x1, (float)y1);
last_x = x1; last_y = y1;
break;
case Element.PathSegmentType.e_cubicto:
x1 = data[data_itr]; ++data_itr;
y1 = data[data_itr]; ++data_itr;
x2 = data[data_itr]; ++data_itr;
y2 = data[data_itr]; ++data_itr;
x3 = data[data_itr]; ++data_itr;
y3 = data[data_itr]; ++data_itr;
gdi_path.AddBezier((float)last_x, (float)last_y,
(float)x1, (float)y1,
(float)x2, (float)y2,
(float)x3, (float)y3);
last_x = x3;
last_y = y3;
break;
case Element.PathSegmentType.e_rect:
{
start_x = last_x = x1 = data[data_itr]; ++data_itr;
start_y = last_y = y1 = data[data_itr]; ++data_itr;
double w = data[data_itr]; ++data_itr;
double h = data[data_itr]; ++data_itr;
x2 = x1 + w;
y2 = y1;
gdi_path.StartFigure();
gdi_path.AddLine((float)x1, (float)y1, (float)x2, (float)y1);
gdi_path.AddLine((float)x2, (float)y1, (float)x2, (float)y2);
gdi_path.AddLine((float)x2, (float)y2, (float)x1, (float)y2);
gdi_path.AddLine((float)x1, (float)y2, (float)x1, (float)y1);
break;
}
case Element.PathSegmentType.e_closepath:
if (last_x != start_x || last_y != start_y)
{
gdi_path.AddLine((float)last_x, (float)last_y, (float)start_x,
(float)start_y);
last_x = start_x; last_y = start_y;
}
break;
default:
System.Diagnostics.Debug.Assert(false);
break;
}
}
GState gs = element.GetGState();
if (element.IsStroked())
{ // ...
}
if (element.IsFilled())
{
gdi_path.FillMode = (element.IsWindingFill() ? FillMode.Winding :
FillMode.Alternate);
if (gs.GetFillColorSpace().GetType() == ColorSpace.Type.e_pattern)
{
// Console.WriteLine("Path has associated pattern");
}
else
{
// ColorPt rgb = new ColorPt();
// gs.GetFillColorSpace().Convert2RGB(gs.GetFillColor(), rgb);
// Color c = Color.FromArgb(255, (int)(rgb.c[0]*255), (int)
(rgb.c[1]*255), (int)(rgb.c[2]*255));
// SolidBrush brush = new SolidBrush(c);
// graphics.FillPath(brush, gdi_path);
}
}
if (element.IsClippingPath())
{
// ...
}
return gdi_path;
}