to study to handle clipping paths also
namespace saan_trying_pathspositioningscaling_3000_OFFSETS_PAGES_TRANSFORMATIONS_MATRIX_GRAPHIKS_STATES_graphics_data_extractions_pagewises
{
//for tekla pdfexchanges the mediabox dont exists
//////private Stack<GraphicsState> graphicsStateStack = new Stack<GraphicsState>();
//////private GraphicsState currentGraphicsState = new GraphicsState();
//////public void EventOccurred(IEventData data, EventType type)
//////{
////// if (type == EventType.RENDER_PATH)
////// {
////// PathRenderInfo renderInfo = (PathRenderInfo)data;
////// ProcessPath(renderInfo);
////// }
////// else if (type == EventType.RENDER_TEXT)
////// {
////// TextRenderInfo renderInfo = (TextRenderInfo)data;
////// ProcessText(renderInfo);
////// }
////// else if (type == EventType.SAVE_GRAPHICS_STATE)
////// {
////// SaveGraphicsState();
////// }
////// else if (type == EventType.RESTORE_GRAPHICS_STATE)
////// {
////// RestoreGraphicsState();
////// }
////// else if (type == EventType.MODIFY_CTM)
////// {
////// ModifyCtm((Matrix)data);
////// }
//////}
//////public ICollection<EventType> GetSupportedEvents()
//////{
////// return new HashSet<EventType>
////// {
////// EventType.RENDER_PATH,
////// EventType.RENDER_TEXT,
////// EventType.SAVE_GRAPHICS_STATE,
////// EventType.RESTORE_GRAPHICS_STATE,
////// EventType.MODIFY_CTM
////// };
//////}
//this is the Graphics and Text extraction Listener
//this not only extracts the graphics it is to extract the texts also
public class GraphicsAndText_ExtractionListener : IEventListener
{
private Stack<GraphicsState> graphicsStateStack = new Stack<GraphicsState>();
private GraphicsState currentGraphicsState = new GraphicsState();
private class GraphicsState
{
public Matrix CurrentCTM { get; set; }
public Matrix CTM;
public Matrix TextMatrix;
public IShape ClippingPath;//I have changed Shape to IShape
public List<IShape> CurrentClippingPath;//I have changed Shape to List<IShape>
// Add more as needed (color, linewidth, etc.)
public GraphicsState Clone()
{
return new GraphicsState
{
CurrentCTM = CloneMatrix(CurrentCTM),
CurrentClippingPath = new List<IShape>(CurrentClippingPath)
};
}
private Matrix CloneMatrix(Matrix original)
{
return new Matrix(
original.Get(Matrix.I11), original.Get(Matrix.I12), original.Get(Matrix.I13),
original.Get(Matrix.I21), original.Get(Matrix.I22), original.Get(Matrix.I23)
);
}
}// private class GraphicsState
private readonly List<string> graphicsData = new List<string>();
private readonly List<string> ListOfStringAsTextDataOnlys = new List<string>();
private readonly List<string> dxfData = new List<string>();
private int currentPageNumber;
private float currentPageWidth;
private float currentPageHeight;
private double double_currentPageDiagonal;
private double percentage_of_current_length___to_current_page_width = 0;
private double percentage_of_current_length___to_current_page_height = 0;
private double percentage_of_current_length___to_current_page_diagonal = 0;
private double double_angle_in_degrees_for_current_line = 0;
private Matrix currentTransformationMatrix = new Matrix();
private Matrix currentSAANTextTransformationMatrix = new Matrix();
public void SetPageInfo(int pageNumber, float pageWidth, float pageHeight)
{
currentPageNumber = pageNumber;
currentPageWidth = pageWidth;
currentPageHeight = pageHeight;
double_currentPageDiagonal = Math.Sqrt(pageWidth * pageWidth + pageHeight * pageHeight);
// Reset graphics state
graphicsStateStack.Clear();
currentGraphicsState = new GraphicsState { CurrentCTM = new Matrix() };
}// public void SetPageInfo(int pageNumber, float pageWidth, float pageHeight)
public void EventOccurred(IEventData data, EventType type)
{
// in this case saan is not handling the clip path changed event
// in this case saan is not handling the clip path changed event
// in this case saan is not handling the clip path changed event
// in this case saan is not handling the clip path changed event
// in this case saan is not handling the clip path changed event
// in this case saan is not handling the clip path changed event
if (type == EventType.RENDER_PATH)
{
PathRenderInfo renderInfo = (PathRenderInfo)data;
string pathDetails = GetPathDetails(renderInfo);
graphicsData.Add(pathDetails);
AddToDxfData(renderInfo, currentPageNumber);
}// if (type == EventType.RENDER_PATH)
//graphiks look ok for the Revit pdf files
//texts are not coming
//////if (type == EventType.END_TEXT)
//////{
////// TextRenderInfo ___textrenderinfo = (TextRenderInfo)data;
////// string ___found_text = ___textrenderinfo.GetText();
////// string TextDetailsFound = GetTextDetails(___textrenderinfo);
////// ListOfStringAsTextDataOnlys.Add(TextDetailsFound);
////// AddTextContentsToToDxfData(___textrenderinfo, currentPageNumber);//to implement
////// // to implement
////// // TextRegionEventFilter .Add(
////// //////PathRenderInfo renderInfo = (PathRenderInfo)data;
////// //////string pathDetails = GetPathDetails(renderInfo);
////// //////graphicsData.Add(pathDetails);
////// //////AddToDxfData(renderInfo, currentPageNumber);
//////}// if (type == EventType.END_TEXT)
else if (type == EventType.RENDER_TEXT)
{
TextRenderInfo ___textrenderinfo = (TextRenderInfo)data;
string ___found_text = ___textrenderinfo.GetText();
string TextDetailsFound = GetTextDetails(___textrenderinfo);
ListOfStringAsTextDataOnlys.Add(TextDetailsFound);
AddTextContentsToToDxfData(___textrenderinfo, currentPageNumber);//to implement
// to implement
// TextRegionEventFilter .Add(
//////PathRenderInfo renderInfo = (PathRenderInfo)data;
//////string pathDetails = GetPathDetails(renderInfo);
//////graphicsData.Add(pathDetails);
//////AddToDxfData(renderInfo, currentPageNumber);
}// if (type == EventType.RENDER_TEXT)
//////if (type == EventType.END_TEXT)
//////{
////// TextRenderInfo ___textrenderinfo = (TextRenderInfo)data;
////// string ___found_text = ___textrenderinfo.GetText();
////// string TextDetailsFound = GetTextDetails(___textrenderinfo);
////// ListOfStringAsTextDataOnlys.Add(TextDetailsFound);
////// AddTextContentsToToDxfData(___textrenderinfo, currentPageNumber);//to implement
////// // to implement
////// // TextRegionEventFilter .Add(
////// //////PathRenderInfo renderInfo = (PathRenderInfo)data;
////// //////string pathDetails = GetPathDetails(renderInfo);
////// //////graphicsData.Add(pathDetails);
////// //////AddToDxfData(renderInfo, currentPageNumber);
//////}// if (type == EventType.END_TEXT)
//////if (type == EventType.BEGIN_TEXT)
//////{
////// TextRenderInfo ___textrenderinfo = (TextRenderInfo)data;
////// string ___found_text = ___textrenderinfo.GetText();
////// string TextDetailsFound = GetTextDetails(___textrenderinfo);
////// ListOfStringAsTextDataOnlys.Add(TextDetailsFound);
////// AddTextContentsToToDxfData(___textrenderinfo, currentPageNumber);//to implement
////// // to implement
////// // TextRegionEventFilter .Add(
////// //////PathRenderInfo renderInfo = (PathRenderInfo)data;
////// //////string pathDetails = GetPathDetails(renderInfo);
////// //////graphicsData.Add(pathDetails);
////// //////AddToDxfData(renderInfo, currentPageNumber);
//////}// if (type == EventType.BEGIN_TEXT)
///
else if (type == EventType.SAVE_GRAPHICS_STATE)
{
graphicsStateStack.Push(new GraphicsState
{
CTM = currentTransformationMatrix.Clone(), TextMatrix = currentSAANTextTransformationMatrix.Clone(), /* etc */
});
}// if (type == EventType.SAVE_GRAPHICS_STATE)
else if (type == EventType.RESTORE_GRAPHICS_STATE)
{
if (graphicsStateStack.Count > 0)
{
var state = graphicsStateStack.Pop();
currentTransformationMatrix = state.CTM;
currentSAANTextTransformationMatrix = state.TextMatrix;
// restore others
}
}// else if (type == EventType.RESTORE_GRAPHICS_STATE)
//////else if (type == EventType.MODIFY_CTM)
//////{
////// var newMatrix = ((CtmEventData)data).GetCtm();
////// currentTransformationMatrix = newMatrix.Multiply(currentTransformationMatrix);
//////}
else if (type == EventType.CLIP_PATH_CHANGED)
{
// var clipPathInfo = (ClipPathInfo)data;
var clipPathInfo = (ClippingPathInfo)data;
//////currentClipShape = clipPathInfo.GetClippingPath();
//////currentClipCtm = clipPathInfo.GetCtm();
///
DETA7.Kernel.Geom.Path currentClipShape___ItsPath = clipPathInfo.GetClippingPath();
Matrix currentClipPathCtm = clipPathInfo.GetCtm();
// store current clip path from clipPathInfo.GetClippingPath()
}
else if (type == EventType.MODIFY_CTM)
{
//to do
//////if (data is DETA7.Kernel.Pdf.Canvas.Parser.Data.ModifyCtmEventData ctmData)
//////{
////// Matrix ctmMatrix = ctmData.GetCtm();
////// currentTransformationMatrix = ctmMatrix.Multiply(currentTransformationMatrix);
//////}// if (data is DETA7.Kernel.Pdf.Canvas.Parser.Data.ModifyCtmEventData ctmData)
}
}// public void EventOccurred(IEventData data, EventType type)
//////private bool IsInsideClip(RectangleF shape, IShape clipShape)
//////{
////// if (clipShape == null)
////// { return true; }
////// return clipShape.IntersectsWith(shape); // or shape is fully contained in clipShape
//////}//private bool IsInsideClip(RectangleF shape, Shape clipShape)
//////private bool IsInsideClip(RectangleF shape, DETA7.Kernel.Geom.Path clipShape)
//////{
////// if (clipShape == null)
////// { return true; }
////// return clipShape.IntersectsWith(shape); // or shape is fully contained in clipShape
//////}//private bool IsInsideClip(RectangleF shape, Shape clipShape)
//////private RectangleF GetBoundingBox(PathRenderInfo renderInfo)
//////{
////// var ctm = renderInfo.GetCtm();
////// var path = renderInfo.GetPath();
////// float minX = float.MaxValue, minY = float.MaxValue;
////// float maxX = float.MinValue, maxY = float.MinValue;
////// foreach (var subpath in path.GetSubpaths())
////// {
////// foreach (var segment in subpath.GetSegments())
////// {
////// foreach (var point in segment.GetBasePoints())
////// {
////// var transformed = ctm.Multiply(point);
////// float x = (float)transformed.Get(0);
////// float y = (float)transformed.Get(1);
////// minX = Math.Min(minX, x);
////// minY = Math.Min(minY, y);
////// maxX = Math.Max(maxX, x);
////// maxY = Math.Max(maxY, y);
////// }
////// }
////// }
////// return new RectangleF(minX, minY, maxX - minX, maxY - minY);
//////}// private RectangleF GetBoundingBox(PathRenderInfo renderInfo)
//////private RectangleF GetBoundingBox(PathRenderInfo renderInfo)
//////{
////// var ctm = renderInfo.GetCtm();
////// var path = renderInfo.GetPath();
////// float minX = float.MaxValue, minY = float.MaxValue;
////// float maxX = float.MinValue, maxY = float.MinValue;
////// foreach (var subpath in path.GetSubpaths())
////// {
////// foreach (var segment in subpath.GetSegments())
////// {
////// foreach (var point in segment.GetBasePoints())
////// {
////// //Vector transformed = ctm.Multiply(point); // ← point is Vector
////// Vector transformed = TransformPoint(renderInfo.GetCtm(), point);
////// float x = (float)transformed.Get(0);
////// float y = (float)transformed.Get(1);
////// minX = Math.Min(minX, x);
////// minY = Math.Min(minY, y);
////// maxX = Math.Max(maxX, x);
////// maxY = Math.Max(maxY, y);
////// }
////// }
////// }
////// return new RectangleF(minX, minY, maxX - minX, maxY - minY);
//////}// private RectangleF GetBoundingBox(PathRenderInfo renderInfo)
//////public Vector TransformPoint(Matrix matrix, Vector point)
//////{
////// float x = point.Get(0);
////// float y = point.Get(1);
////// //////float newX = matrix.Get(0, 0) * x + matrix.Get(0, 1) * y + matrix.Get(0, 2);
////// //////float newY = matrix.Get(1, 0) * x + matrix.Get(1, 1) * y + matrix.Get(1, 2);
////// float newX = matrix.Get(0, 0) * x + matrix.Get(0, 1) * y + matrix.Get(0, 2);
////// float newY = matrix.Get(1, 0) * x + matrix.Get(1, 1) * y + matrix.Get(1, 2);
////// return new Vector(newX, newY, 1);
//////}
private float[] TransformPoint(Vector point, Matrix matrix)
{
float x = point.Get(Vector.I1);
float y = point.Get(Vector.I2);
float transformedX = matrix.Get(Matrix.I11) * x + matrix.Get(Matrix.I12) * y + matrix.Get(Matrix.I13);
float transformedY = matrix.Get(Matrix.I21) * x + matrix.Get(Matrix.I22) * y + matrix.Get(Matrix.I23);
return new float[] { transformedX, transformedY };
}// private float[] TransformPoint(Vector point, Matrix matrix)
private bool IsInsideClip(RectangleF rect, System.Drawing.Drawing2D.GraphicsPath clipShape)
{
if (clipShape == null)
return true;
using (var region = new Region(clipShape))
{
return region.IsVisible(rect);
}//using (var region = new Region(clipShape))
}// private bool IsInsideClip(RectangleF rect, System.Drawing.Drawing2D.GraphicsPath clipShape)
private RectangleF GetBoundingBox(PathRenderInfo renderInfo)
{
Matrix ctm = renderInfo.GetCtm();
var path = renderInfo.GetPath();
float minX = float.MaxValue, minY = float.MaxValue;
float maxX = float.MinValue, maxY = float.MinValue;
foreach (var subpath in path.GetSubpaths())
{
foreach (var segment in subpath.GetSegments())
{
foreach (var point in segment.GetBasePoints())
{
//////float x = point.Get(Vector.I1); // index 0
//////float y = point.Get(Vector.I2); // index 1
///
float[] transformed = TransformPoint(point, ctm);
float x = transformed[0];
float y = transformed[1];
float transformedX = ctm.Get(Matrix.I11) * x + ctm.Get(Matrix.I12) * y + ctm.Get(Matrix.I13);
float transformedY = ctm.Get(Matrix.I21) * x + ctm.Get(Matrix.I22) * y + ctm.Get(Matrix.I23);
minX = Math.Min(minX, transformedX);
minY = Math.Min(minY, transformedY);
maxX = Math.Max(maxX, transformedX);
maxY = Math.Max(maxY, transformedY);
}//foreach (var point in segment.GetBasePoints())
}//foreach (var segment in subpath.GetSegments())
}// foreach (var subpath in path.GetSubpaths())
return new RectangleF(minX, minY, maxX - minX, maxY - minY);
}// private RectangleF GetBoundingBox(PathRenderInfo renderInfo)
//////public ICollection<EventType> GetSupportedEvents()
//////{
////// return new HashSet<EventType> { EventType.RENDER_PATH };
//////}// public ICollection<EventType> GetSupportedEvents()
//////By doing this, you have:
//////Operator
//////Implementation
//////q/Q
//////SAVE_GRAPHICS_STATE / RESTORE_GRAPHICS_STATE with stack
//////cm
//////MODIFY_CTM via matrix multiplication
//////W/W*
//////Intercepted inside RENDER_PATH, stored manually
//////CTM use
//////Via renderInfo.GetCtm() + manual matrix chain
//////Clipping
//////Handled via shape list and rough AABB filter
public ICollection<EventType> GetSupportedEvents()
{
///saan has not handled the CLIP_PATH_CHANGED EVENT IN THIS CASE AND THE DATA ARE COMING OK FOR THE BLUEBEAM PRINTING CASES
return new HashSet<EventType>
{
EventType.BEGIN_TEXT,
EventType.RENDER_PATH,
EventType.RENDER_TEXT,
EventType.END_TEXT,
//EventType.SAVE_GRAPHICS_STATE,
// EventType.RESTORE_GRAPHICS_STATE,
//EventType.MODIFY_CTM
// EventType.BEGIN_TEXT,
// EventType.END_TEXT,
// EventType.RENDER_PATH,
// EventType.RENDER_TEXT,
EventType.SAVE_GRAPHICS_STATE,
EventType.RESTORE_GRAPHICS_STATE,
EventType.MODIFY_CTM,
EventType.CLIP_PATH_CHANGED
};
}
private string GetPathDetails(PathRenderInfo renderInfo)
{
StringBuilder details = new StringBuilder();
details.AppendLine($"Page Number: {currentPageNumber}, Page Width: {currentPageWidth}, Page Height: {currentPageHeight}");
details.AppendLine("Path Details:");
details.AppendLine($"Operation: {renderInfo.GetOperation()}");
details.AppendLine($"Rule: {renderInfo.GetRule()}");
double ___double_type_page_width = (double)currentPageWidth;
double ___double_type_page_height = (double)currentPageHeight;
double ___double_current_page_diagonal_length = Math.Sqrt(___double_type_page_width * ___double_type_page_width + ___double_type_page_height * ___double_type_page_height);
foreach (Subpath subpath in renderInfo.GetPath().GetSubpaths())
{
foreach (IShape shape in subpath.GetSegments())
{
if (shape is Line)
{
Line line = (Line)shape;
float[] start = TransformPoint(line.p1, renderInfo.GetCtm());
float[] end = TransformPoint(line.p2, renderInfo.GetCtm());
details.AppendLine($"Line: Start({start[0]}, {start[1]}) - End({end[0]}, {end[1]})");
}
else if (shape is BezierCurve)
{
BezierCurve curve = (BezierCurve)shape;
int controlPointCounter = 0;
foreach (DETA7.Kernel.Geom.Point controlPoint in curve.controlPoints)
{
float[] transformedControlPoint = TransformPoint(controlPoint, renderInfo.GetCtm());
details.AppendLine($"Curve: Control Point {controlPointCounter} - x: {transformedControlPoint[0]}, y: {transformedControlPoint[1]}");
controlPointCounter++;
}// foreach (DETA7.Kernel.Geom.Point controlPoint in curve.controlPoints)
}// else if (shape is BezierCurve)
}// foreach (IShape shape in subpath.GetSegments())
}// foreach (Subpath subpath in renderInfo.GetPath().GetSubpaths())
return details.ToString();
}// private string GetPathDetails(PathRenderInfo renderInfo)
//////private string GetTextDetails(TextRenderInfo FoundTextRenderInfo)
//////{
////// StringBuilder detailsForTexts = new StringBuilder();
////// // To implement
////// detailsForTexts.AppendLine("Text= " +FoundTextRenderInfo.text);
////// detailsForTexts.AppendLine("textMatrix = " + FoundTextRenderInfo.textMatrix.ToString());
////// detailsForTexts.AppendLine("GetUnscaledWidth = " + FoundTextRenderInfo.GetUnscaledWidth().ToString());
////// return detailsForTexts.ToString();
//////}//private string GetTextDetails(TextRenderInfo FoundTextRenderInfo)
//////private void AddTextContentsToToDxfData(TextRenderInfo FoundTextRenderInfo, int pageNumber)
//////{
////// float offsetspageswises = 30000 * (pageNumber - 1);
////// DETA7.Kernel.Geom.Point TextInsertionsPoint= FoundTextRenderInfo.
////// float[] transformedControlPoint = TransformPoint(controlPoint, FoundTextRenderInfo.GetCtm());
////// To implement dxf generations codes
////// renderInfo.
//////}//private void AddTextContentsToToDxfData(TextRenderInfo renderInfo, int pageNumber)
/// <summary>
///
///
///
///
///
/// </summary>
/// <param name="renderInfo"></param>
/// <param name="pageNumber"></param>
private string GetTextDetails(TextRenderInfo FoundTextRenderInfo)
{
StringBuilder detailsForTexts = new StringBuilder();
detailsForTexts.AppendLine("Text = " + FoundTextRenderInfo.GetText());
detailsForTexts.AppendLine("Text Matrix = " + FoundTextRenderInfo.GetTextMatrix().ToString());
detailsForTexts.AppendLine("Unscaled Width = " + FoundTextRenderInfo.GetUnscaledWidth().ToString());
LineSegment baseline = FoundTextRenderInfo.GetBaseline();
detailsForTexts.AppendLine("Baseline Start = " + baseline.GetStartPoint().ToString());
detailsForTexts.AppendLine("Baseline End = " + baseline.GetEndPoint().ToString());
detailsForTexts.AppendLine("Font Size = " + FoundTextRenderInfo.GetFontSize().ToString());
detailsForTexts.AppendLine("Text Rise = " + FoundTextRenderInfo.GetRise().ToString());
return detailsForTexts.ToString();
}//private string GetTextDetails(TextRenderInfo FoundTextRenderInfo)
private void AddTextContentsToToDxfData(TextRenderInfo FoundTextRenderInfo, int pageNumber)
{
float offsetspageswises = 30000 * (pageNumber - 1);
LineSegment baseline = FoundTextRenderInfo.GetBaseline();
Vector startPoint = baseline.GetStartPoint();
float x = startPoint.Get(Vector.I1);
float y = startPoint.Get(Vector.I2);
string text = FoundTextRenderInfo.GetText();
// DXF TEXT entity
// TO DO
// string dxfTextEntity = $"0\nTEXT\n8\n0\n10\n{offsetspageswises + x}\n20\n{y}\n30\n0.0\n40\n{FoundTextRenderInfo.GetFontSize()}\n1\n{text}\n";
// LineSegment baseline = FoundTextRenderInfo.GetBaseline();
Vector start = baseline.GetStartPoint();
Vector end = baseline.GetEndPoint();
float dx = end.Get(Vector.I1) - start.Get(Vector.I1);
float dy = end.Get(Vector.I2) - start.Get(Vector.I2);
float rotationAngle = (float)(Math.Atan2(dy, dx) * (180.0 / Math.PI)); // DXF expects degrees
float fontHeight = FoundTextRenderInfo.GetFontSize();
float fontWidth = FoundTextRenderInfo.GetUnscaledWidth(); // Optional: scale this if needed
LineSegment ascentLine = FoundTextRenderInfo.GetAscentLine();
float textHeight = ascentLine.GetLength(); // More accurate than GetFontSize()
// string dxfTextEntity = $"0\nTEXT\n8\n0\n10\n{offsetspageswises + x}\n20\n{y}\n30\n0.0\n40\n{FoundTextRenderInfo.GetFontSize()}\n1\n{text}";
//this also dont put the proper text height on dxf (sometimes texts look larger on dxf(than the pdf) sometimes looks smaller in dxf than it is in pdf(i think we need to do some additional rendering calculations for the text heights and text widths
/// string dxfTextEntity = $"0\nTEXT\n8\n0\n10\n{offsetspageswises + x}\n20\n{y}\n30\n0.0\n40\n{fontHeight}\n50\n{rotationAngle}\n1\n{text}";
///
//////detailsForTexts.AppendLine("Text = " + FoundTextRenderInfo.GetText());
//////detailsForTexts.AppendLine("Text Matrix = " + FoundTextRenderInfo.GetTextMatrix().ToString());
//////detailsForTexts.AppendLine("Unscaled Width = " + FoundTextRenderInfo.GetUnscaledWidth().ToString());
//////LineSegment baseline = FoundTextRenderInfo.GetBaseline();
//////detailsForTexts.AppendLine("Baseline Start = " + baseline.GetStartPoint().ToString());
//////detailsForTexts.AppendLine("Baseline End = " + baseline.GetEndPoint().ToString());
//////detailsForTexts.AppendLine("Font Size = " + FoundTextRenderInfo.GetFontSize().ToString());
//////detailsForTexts.AppendLine("Text Rise = " + FoundTextRenderInfo.GetRise().ToString());
float fontSize = FoundTextRenderInfo.GetFontSize();
// string fontName= FoundTextRenderInfo.GetFont()fontName
string fontName = FoundTextRenderInfo.GetFont().GetFontProgram().GetFontNames().GetFontName();
//string color = FoundTextRenderInfo.GetFillColor().ToString();
string color = FoundTextRenderInfo.GetFillColor().ToString();
float wordspacingfound = FoundTextRenderInfo.GetWordSpacing();
int aciColor = 0;
int r = 0;
int g = 0;
int b = 0;
try
{
DETA7.Kernel.Colors.Color fillColor = FoundTextRenderInfo.GetFillColor();
r = (int)(fillColor.GetColorValue()[0] * 255);
g = (int)(fillColor.GetColorValue()[1] * 255);
b = (int)(fillColor.GetColorValue()[2] * 255);
aciColor = GetClosestAciColor(r, g, b); // You can define this function or use fixed values
}
catch (Exception excp)
{
aciColor = 6;
}
// Create layer name
string layerName = $"{fontSize}_{rotationAngle}_{wordspacingfound}_{fontName}_{color}";
layerName = layerName.Replace(",", "_")
.Replace(".", "_").Replace(";", "_").Replace(" ", "_")
.Replace("+", "_").Replace("/", "_").Replace("\\", "_")
.Replace("DETA7_Kernel_Colors_", "");
// string dxfTextEntity = $"0\nTEXT\n8\n{layerName}\n10\n{offsetspageswises + x}\n20\n{y}\n30\n0.0\n40\n{textHeight}\n50\n{rotationAngle}\n1\n{text}";
string dxfTextEntity = $"0\nTEXT\n8\n{layerName}\n10\n{offsetspageswises + x}\n20\n{y}\n30\n0.0\n40\n{textHeight}\n50\n{rotationAngle}\n62\n{aciColor}\n1\n{text}";
string trueColor = $"420\n{(r << 16) + (g << 8) + b}";
//sanjoynath text
string dxfTextEntity_saans = $"0\nTEXT\n8\n0\n10\n{offsetspageswises + x}\n20\n{y}\n30\n0.0\n40\n{0.01}\n50\n{rotationAngle}\n1\n"+"SANJOYNATH";
dxfData.Add(dxfTextEntity);
dxfData.Add(dxfTextEntity_saans);//SanjoyNath texts
// Create layer name
// string layerName = $"{fontSize}_{rotationAngle}_{fontName}_{color}";
// Add
//////// Add text to DXF content
//////dxfContent.AppendLine("0");
//////dxfContent.AppendLine("TEXT");
//////dxfContent.AppendLine("8");
//////dxfContent.AppendLine(layerName);
//////dxfContent.AppendLine("10");
//////dxfContent.AppendLine(offsetX.ToString());
//////dxfContent.AppendLine("20");
//////dxfContent.AppendLine(offsetY.ToString());
//////dxfContent.AppendLine("40");
//////dxfContent.AppendLine(fontSize.ToString());
//////dxfContent.AppendLine("50");
//////dxfContent.AppendLine(rotationAngle.ToString());
//////dxfContent.AppendLine("1");
//////dxfContent.AppendLine(text);
}//private void AddTextContentsToToDxfData(TextRenderInfo FoundTextRenderInfo, int pageNumber)
private int GetClosestAciColor(int r, int g, int b)
{
// Basic ACI color map (partial, can be extended)
Dictionary<int, (int R, int G, int B)> aciColors = new Dictionary<int, (int, int, int)>
{
{1, (255, 0, 0)}, // Red
{2, (255, 255, 0)}, // Yellow
{3, (0, 255, 0)}, // Green
{4, (0, 255, 255)}, // Cyan
{5, (0, 0, 255)}, // Blue
{6, (255, 0, 255)}, // Magenta
{7, (255, 255, 255)}, // White
{8, (128, 128, 128)}, // Gray
{9, (192, 192, 192)} // Light Gray
};
int closestIndex = 7; // Default to white
double minDistance = double.MaxValue;
foreach (var kvp in aciColors)
{
int aci = kvp.Key;
var (r2, g2, b2) = kvp.Value;
double distance = Math.Sqrt(Math.Pow(r - r2, 2) + Math.Pow(g - g2, 2) + Math.Pow(b - b2, 2));
if (distance < minDistance)
{
minDistance = distance;
closestIndex = aci;
}
}
return closestIndex;
}//private int GetClosestAciColor(int r, int g, int b)
private void AddToDxfData(PathRenderInfo renderInfo, int pageNumber)
{
float offsetspageswises = 30000 * (pageNumber - 1);
// Extract styling info
float lineWidth = renderInfo.GetLineWidth();
string lineType = renderInfo.GetLineDashPattern()?.ToString() ?? "Continuous";
string lineCap = renderInfo.GetLineCapStyle().ToString();
string lineJoin = renderInfo.GetLineJoinStyle().ToString();
DETA7.Kernel.Colors.Color strokeColor = renderInfo.GetStrokeColor();
//these data are pushed to listener before processing starts
double ___double_type_page_width = (double)currentPageWidth;
double ___double_type_page_height = (double)currentPageHeight;
double ___double_current_page_diagonal_length = Math.Sqrt(___double_type_page_width * ___double_type_page_width + ___double_type_page_height * ___double_type_page_height);
string STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED = "";
//////int r = (int)(strokeColor.GetColorValue()[0] * 255);
//////int g = (int)(strokeColor.GetColorValue()[1] * 255);
//////int b = (int)(strokeColor.GetColorValue()[2] * 255);
//////int aciColor = GetClosestAciColor(r, g, b);
int aciColor = 0;
int r = 0;
int g = 0;
int b = 0;
try
{
/// DETA7.Kernel.Colors.Color fillColor = FoundTextRenderInfo.GetFillColor();
r = (int)(strokeColor.GetColorValue()[0] * 255);
g = (int)(strokeColor.GetColorValue()[1] * 255);
b = (int)(strokeColor.GetColorValue()[2] * 255);
aciColor = GetClosestAciColor(r, g, b); // You can define this function or use fixed values
}
catch (Exception excp)
{
aciColor = 6;
}
// Create DXF-safe layer name
// string rawLayerName = $"{lineWidth}_{lineType}_{lineCap}_{lineJoin}_{aciColor}";
//12_5424_0_GHQWKA_Arial_DETA7_Kernel_Colors_DeviceGray
//strokeColor
string rawLayerName = $"{lineWidth}_{lineType}_{lineCap}_{lineJoin}_{strokeColor.ToString()}";
string layerName = System.Text.RegularExpressions.Regex.Replace(rawLayerName, @"[^a-zA-Z0-9_]", "_")
.Replace("DETA7_Kernel_Colors_","");
////// layerName = layerName +"_"+ renderInfo.GetPath().GetSubpaths().Count;
int subpathcount = 0;
int linecountinshape = 0;
int BezierCurvecountinshape = 0;
subpathcount = renderInfo.GetPath().GetSubpaths().Count;
foreach (Subpath subpath in renderInfo.GetPath().GetSubpaths())
{
PdfGraphicsExtractor_to_singles_30000_offsets_dxf____trying_with_new_scales_translations
.shape_counter_in_this_page++;
List<IShape> segments = subpath.GetSegments().ToList();
// Ensure loop closure if needed
// if (segments.Count > 1 && segments[0] is Line first && segments[1] is Line last)
if (segments.Count > 1 && segments[0] is Line first && segments[segments.Count-1] is Line last)
{
if (!PointsEqual(first.p1, last.p2))
{
segments.Add(new Line(last.p2, first.p1));
//SAAN ADDS THESE
STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED = "CLOSED";
aciColor = 3;
if (STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED.Contains("CLOSED"))
{
//dont add
}//if(!STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED.Contains("CLOSED"))
else
{
layerName = layerName + "_" + STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED;
}//end of else of if (STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED.Contains("CLOSED"))
}//if (!PointsEqual(first.p1, last.p2))
else
{
//SAAN ADDS THESE
STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED = "OPEN";
aciColor = 1;
////// layerName = layerName + "_" + STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED;
///
if (STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED.Contains("OPEN"))
{
//dont add
}//if(!STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED.Contains("OPEN"))
else
{
layerName = layerName + "_" + STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED;
}//end of else of if (STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED.Contains("OPEN"))
}//END OF ELSE OF if (!PointsEqual(first.p1, last.p2))
}// if (segments.Count > 1 && segments[0] is Line first && segments[segments.Count-1] is Line last)
// layerName = layerName + "_" + renderInfo.GetPath().GetSubpaths().Count;
foreach (IShape shape in segments)
{
if (shape is Line line)
{
linecountinshape++;
float[] start = TransformPoint(line.p1, renderInfo.GetCtm());
float[] end = TransformPoint(line.p2, renderInfo.GetCtm());
double ___x1 = 0;
double ___y1 = 0;
double ___x2 = 0;
double ___y2 = 0;
___x1 = (double)start[0];
___y1 = (double)start[1];
___x2 = (double)end[0];
___y2 = (double)end[1];
double ___double_lines_length = Math.Sqrt(((___x2 - ___x1) * (___x2 - ___x1)) + ((___y2 - ___y1) * (___y2 - ___y1)));
___double_current_page_diagonal_length = Math.Max(___double_current_page_diagonal_length, 0.0000001);
int ___double_1000times_integered_proportion_to_diagonal_length =
// (int)((___double_lines_length / ___double_current_page_diagonal_length) * 1000);
(int)((___double_lines_length / ___double_current_page_diagonal_length) * 1000);
// string dxfLine = $"0\nLINE\n8\n{layerName}\n10\n{offsetspageswises + start[0]}\n20\n{start[1]}\n30\n0.0\n11\n{offsetspageswises + end[0]}\n21\n{end[1]}\n31\n0.0\n62\n{aciColor}\n370\n{(int)(lineWidth * 100)}";
double ___delta_y = (___y2 - ___y1);
double ___delta_x = (___x2 - ___x1);
// ___delta_x = Math.Max(___delta_x, 0.0000000001);
___delta_x = Math.Max(___delta_x,Double.MinValue);
// double ___slope_in_radians = Math.Atan(Math.Abs(___delta_y) / Math.Abs( ___delta_x));
double ___slope_in_radians = Math.Atan2(Math.Abs(___delta_y) , Math.Abs(___delta_x));
// float rotationAngle = (float)(Math.Atan2(dy, dx) * (180.0 / Math.PI)); // DXF expects degrees
double ___slope_in_degrees = ___slope_in_radians * 180 / Math.PI;
int ___intslopeindegrees =Math.Abs( (int)___slope_in_degrees);
//SAAN ADDS THESE
STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED = "LINEAR";
// aciColor = 22;
aciColor
=
___double_1000times_integered_proportion_to_diagonal_length % 253;
// layerName = layerName + "_" + STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED;
if (STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED.Contains("LINEAR"))
{
//dont add
}//if(!STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED.Contains("LINEAR"))
else
{
layerName = layerName + "_" + STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED;
}//end of else of if (STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED.Contains("LINEAR"))
int ___shape_counter
=
PdfGraphicsExtractor_to_singles_30000_offsets_dxf____trying_with_new_scales_translations.shape_counter_in_this_page;
string dxfLine = $"0\nLINE\n8\n{layerName}_{___shape_counter}_{STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED}_{___double_1000times_integered_proportion_to_diagonal_length}_{___intslopeindegrees}\n10\n{offsetspageswises + start[0]}\n20\n{start[1]}\n30\n0.0\n11\n{offsetspageswises + end[0]}\n21\n{end[1]}\n31\n0.0\n62\n{aciColor}";
dxfData.Add(dxfLine);
}
else if (shape is BezierCurve curve)
{
BezierCurvecountinshape++;
float[] start = TransformPoint(curve.controlPoints[0], renderInfo.GetCtm());
float[] control1 = TransformPoint(curve.controlPoints[1], renderInfo.GetCtm());
float[] control2 = TransformPoint(curve.controlPoints[2], renderInfo.GetCtm());
float[] end = TransformPoint(curve.controlPoints[3], renderInfo.GetCtm());
int numSegments = 10;
float tStep = 1.0f / numSegments;
float[] prevPoint = start;
for (int i = 1; i <= numSegments; i++)
{
float t = i * tStep;
float[] point = CalculateBezierPoint(t, start, control1, control2, end);
/// string dxfCurveSegment = $"0\nLINE\n8\n{layerName}\n10\n{offsetspageswises + prevPoint[0]}\n20\n{prevPoint[1]}\n30\n0.0\n11\n{offsetspageswises + point[0]}\n21\n{point[1]}\n31\n0.0\n62\n{aciColor}\n370\n{(int)(lineWidth * 100)}";
//SAAN ADDS THESE
STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED = "BEZIERED";
aciColor = 11;
if (STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED.Contains("BEZIERED"))
{
//dont add
}//if(!STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED.Contains("BEZIERED"))
else
{
layerName = layerName + "_" + STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED;
}//end of else of if (STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED.Contains("BEZIERED"))
int ___shape_counter
=
PdfGraphicsExtractor_to_singles_30000_offsets_dxf____trying_with_new_scales_translations.shape_counter_in_this_page;
string dxfCurveSegment = $"0\nLINE\n8\n{layerName}_{___shape_counter}_{STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED}\n10\n{offsetspageswises + prevPoint[0]}\n20\n{prevPoint[1]}\n30\n0.0\n11\n{offsetspageswises + point[0]}\n21\n{point[1]}\n31\n0.0\n62\n{aciColor}";
// string dxfCurveSegment = $"0\nLINE\n8\n{layerName}_{STRING_LINEPATHCATEGORY___CLOSED_OPEN_LINEAR_BEZIERED}\n10\n{offsetspageswises + prevPoint[0]}\n20\n{prevPoint[1]}\n30\n0.0\n11\n{offsetspageswises + point[0]}\n21\n{point[1]}\n31\n0.0\n62\n{aciColor}";
dxfData.Add(dxfCurveSegment);
prevPoint = point;
}//for (int i = 1; i <= numSegments; i++)
}// else if (shape is BezierCurve curve)
}// foreach (IShape shape in segments)
}// foreach (Subpath subpath in renderInfo.GetPath().GetSubpaths())
///cant we add all the LINE to dxf after all the data accumulations are done???????? if we can do that then we can filter things with more proper layer names such that we can filter the data more properly with the global conditions
///for each path there are several subpaths and several line shapes several beziere shapes and classifying these line shapes , beziere shapes closedness of polygons , if the curve is like circle or if that is like splines or if these total path objects semantically looks like ellipse or circles or rectangles or if there are object bounding box AABB like properties then we can accumulate all these things properly
/////if we can put the informations to the layers of these objects in the dxf files then it is more helpful to extract more meaningfull informations for engineering drawings
}//// private void AddToDxfData(PathRenderInfo renderInfo, int pageNumber)
// Helper to check if two points are equal within a tolerance
private bool PointsEqual(DETA7.Kernel.Geom.Point p1, DETA7.Kernel.Geom.Point p2, float tolerance = 0.01f)
{
return Math.Abs(p1.GetX() - p2.GetX()) < tolerance && Math.Abs(p1.GetY() - p2.GetY()) < tolerance;
}//private bool PointsEqual(DETA7.Kernel.Geom.Point p1, DETA7.Kernel.Geom.Point p2, float tolerance = 0.01f)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// NOT IN USE
/// </summary>
/// <param name="renderInfo"></param>
/// <param name="pageNumber"></param>
private void AddToDxfData___THISWASWORKINGNOWENHANCING(PathRenderInfo renderInfo, int pageNumber)
{
float offsetspageswises = 30000 * (pageNumber - 1);
foreach (Subpath subpath in renderInfo.GetPath().GetSubpaths())
{
foreach (IShape shape in subpath.GetSegments())
{
if (shape is Line)
{
Line line = (Line)shape;
float[] start = TransformPoint(line.p1, renderInfo.GetCtm());
float[] end = TransformPoint(line.p2, renderInfo.GetCtm());
dxfData.Add($"0\nLINE\n8\n0\n10\n{offsetspageswises + start[0]}\n20\n{start[1]}\n30\n0.0\n11\n{offsetspageswises + end[0]}\n21\n{end[1]}\n31\n0.0");
}
else if (shape is BezierCurve)
{
BezierCurve curve = (BezierCurve)shape;
float[] start = TransformPoint(curve.controlPoints[0], renderInfo.GetCtm());
float[] control1 = TransformPoint(curve.controlPoints[1], renderInfo.GetCtm());
float[] control2 = TransformPoint(curve.controlPoints[2], renderInfo.GetCtm());
float[] end = TransformPoint(curve.controlPoints[3], renderInfo.GetCtm());
// Approximate the Bezier curve with a series of lines
int numSegments = 10; // Number of line segments to approximate the curve
float tStep = 1.0f / numSegments;
float[] prevPoint = start;
for (int i = 1; i <= numSegments; i++)
{
float t = i * tStep;
float[] point = CalculateBezierPoint(t, start, control1, control2, end);
dxfData.Add($"0\nLINE\n8\n0\n10\n{offsetspageswises + prevPoint[0]}\n20\n{prevPoint[1]}\n30\n0.0\n11\n{offsetspageswises + point[0]}\n21\n{point[1]}\n31\n0.0");
prevPoint = point;
}// for (int i = 1; i <= numSegments; i++)
}// else if (shape is BezierCurve)
}// foreach (IShape shape in subpath.GetSegments())
}// foreach (Subpath subpath in renderInfo.GetPath().GetSubpaths())
}// private void AddToDxfData(PathRenderInfo renderInfo, int pageNumber)
private float[] CalculateBezierPoint(float t, float[] p0, float[] p1, float[] p2, float[] p3)
{
float u = 1 - t;
float tt = t * t;
float uu = u * u;
float uuu = uu * u;
float ttt = tt * t;
float[] point = new float[2];
point[0] = uuu * p0[0]; // uuu * p0
point[0] += 3 * uu * t * p1[0]; // 3 * uu * t * p1
point[0] += 3 * u * tt * p2[0]; // 3 * u * tt * p2
point[0] += ttt * p3[0]; // ttt * p3
point[1] = uuu * p0[1]; // uuu * p0
point[1] += 3 * uu * t * p1[1]; // 3 * uu * t * p1
point[1] += 3 * u * tt * p2[1]; // 3 * u * tt * p2
point[1] += ttt * p3[1]; // ttt * p3
return point;
}// private float[] CalculateBezierPoint(float t, float[] p0, float[] p1, float[] p2, float[] p3)
////////////private float[] TransformPoint(Vector point, Matrix matrix)
////////////{
//////////// float x = point.Get(Vector.I1);
//////////// float y = point.Get(Vector.I2);
//////////// float transformedX = matrix.Get(Matrix.I11) * x + matrix.Get(Matrix.I12) * y + matrix.Get(Matrix.I13);
//////////// float transformedY = matrix.Get(Matrix.I21) * x + matrix.Get(Matrix.I22) * y + matrix.Get(Matrix.I23);
//////////// return new float[] { transformedX, transformedY };
////////////}// private float[] TransformPoint(Vector point, Matrix matrix)
//////private float[] TransformPoint(DETA7.Kernel.Geom.Point point, Matrix matrix)
//////{
////// float x = (float)point.GetX();
////// float y = (float)point.GetY();
////// float transformedX = matrix.Get(Matrix.I11) * x + matrix.Get(Matrix.I12) * y + matrix.Get(Matrix.I13);
////// float transformedY = matrix.Get(Matrix.I21) * x + matrix.Get(Matrix.I22) * y + matrix.Get(Matrix.I23);
////// return new float[] { transformedX, transformedY };
//////}// private float[] TransformPoint(DETA7.Kernel.Geom.Point point, Matrix matrix)
private float[] TransformPoint(Matrix matrix , Vector point)
{
float x = point.Get(Vector.I1);
float y = point.Get(Vector.I2);
float transformedX = matrix.Get(Matrix.I11) * x + matrix.Get(Matrix.I12) * y + matrix.Get(Matrix.I13);
float transformedY = matrix.Get(Matrix.I21) * x + matrix.Get(Matrix.I22) * y + matrix.Get(Matrix.I23);
return new float[] { transformedX, transformedY };
}// private float[] TransformPoint(Vector point, Matrix matrix)
private float[] TransformPoint(DETA7.Kernel.Geom.Point point, Matrix matrix)
{
float x = (float)point.GetX();
float y = (float)point.GetY();
float transformedX = matrix.Get(Matrix.I11) * x + matrix.Get(Matrix.I12) * y + matrix.Get(Matrix.I13);
float transformedY = matrix.Get(Matrix.I21) * x + matrix.Get(Matrix.I22) * y + matrix.Get(Matrix.I23);
return new float[] { transformedX, transformedY };
}// private float[] TransformPoint(DETA7.Kernel.Geom.Point point, Matrix matrix)
public void WriteGraphicsData(string outputFilePath)
{
graphicsData.AddRange(ListOfStringAsTextDataOnlys);
File.WriteAllLines(outputFilePath, graphicsData);
}// public void WriteGraphicsData(string outputFilePath)
public void WriteDxfData(string outputFilePath)
{
List<string> dxfContent = new List<string>();
List<string> dxfHeader = new List<string>
{
"0",
"SECTION",
"2",
"HEADER",
"0",
"ENDSEC",
"0",
"SECTION",
"2",
"TABLES",
"0",
"ENDSEC",
"0",
"SECTION",
"2",
"BLOCKS",
"0",
"ENDSEC",
"0",
"SECTION",
"2",
"ENTITIES"
};
List<string> dxfFooter = new List<string>
{
"0",
"ENDSEC",
"0",
"SECTION",
"2",
"OBJECTS",
"0",
"ENDSEC",
"0",
"EOF"
};
dxfContent = new List<string>();
dxfContent.AddRange(dxfHeader);
dxfContent.AddRange(dxfData);
dxfContent.AddRange(dxfFooter);
File.WriteAllLines(outputFilePath, dxfContent);
}// public void WriteDxfData(string outputFilePath)
}// public class GraphicsAndText_ExtractionListener : IEventListener
public class DxfSmartEngineeringTextGrouper : IEventListener
{
private readonly List<TextChunk___DxfSmartEngineeringTextGrouper> allChunks = new List<TextChunk___DxfSmartEngineeringTextGrouper>();
public void EventOccurred(IEventData data, EventType type)
{
if (type != EventType.RENDER_TEXT) return;
var info = (TextRenderInfo)data;
var baseline = info.GetBaseline();
var start = baseline.GetStartPoint();
var end = baseline.GetEndPoint();
var baselineVec = end.Subtract(start);
var angle = (float)Math.Atan2(baselineVec.Get(1), baselineVec.Get(0));
var width = baselineVec.Length();
allChunks.Add(new TextChunk___DxfSmartEngineeringTextGrouper
{
Text = info.GetText(),
X = start.Get(0),
Y = start.Get(1),
Width = width,
Angle = angle,
BaselineDirection = baselineVec.Normalize(),
FontName = info.GetFont().GetFontProgram().ToString(), // Simplified extraction
FontSize = info.GetFontSize(),
Color = info.GetFillColor()?.ToString() ?? "Black"
});
}
public ICollection<EventType> GetSupportedEvents() => new HashSet<EventType> { EventType.RENDER_TEXT };
public List<TextGroup> GroupTextChunks()
{
var groups = new List<TextGroup>();
const float proximityThreshold = 2.0f;//need to calculate with average and standard deviations of font heights (in dxf user spaces) within the page
const float angleTolerance = 0.06f;// 0.02f;
foreach (TextChunk___DxfSmartEngineeringTextGrouper chunk in allChunks)
{
var matchedGroup = groups.FirstOrDefault(g =>
Math.Abs(g.Angle - chunk.Angle) < angleTolerance &&
// g.BaselineDirection.Dot(chunk.BaselineDirection) > 0.99 &&
g.BaselineDirection.Dot(chunk.BaselineDirection) > 0.9 &&
g.FontName == chunk.FontName &&
// g.FontSize == chunk.FontSize &&
g.Color == chunk.Color &&
g.IsNearby(chunk, proximityThreshold));
if (matchedGroup == null)
{
matchedGroup = new TextGroup
{
Angle = chunk.Angle,
FontName = chunk.FontName,
FontSize = chunk.FontSize,
Color = chunk.Color.Replace("DETA7.Kernel.Colors.",""),
BaselineDirection = chunk.BaselineDirection
};
groups.Add(matchedGroup);
}
matchedGroup.Chunks.Add(chunk);
}
// Sort each group by position along baseline
foreach (var group in groups)
{
group.Chunks.Sort((a, b) => a.ProjectedPosition(group).CompareTo(b.ProjectedPosition(group)));
}
return groups;
}
public class TextChunk___DxfSmartEngineeringTextGrouper
{
public string Text;
public float X, Y, Width, Angle, FontSize;
public string FontName, Color;
public Vector BaselineDirection;
public Vector Position => new Vector(X, Y, 0);
public float ProjectedPosition(TextGroup g) =>
Position.Subtract(g.Chunks[0].Position).Dot(g.BaselineDirection);
}// public class TextChunk___DxfSmartEngineeringTextGrouper
public class TextGroup
{
public List<TextChunk___DxfSmartEngineeringTextGrouper> Chunks = new List<TextChunk___DxfSmartEngineeringTextGrouper>();
public string FontName, Color;
public float FontSize, Angle;
public Vector BaselineDirection;
public float text_x, text_y;
public bool IsNearby(TextChunk___DxfSmartEngineeringTextGrouper c, float threshold)
{
return Chunks.Any(existing =>
Math.Abs(existing.ProjectedPosition(this) - c.ProjectedPosition(this)) < threshold);
}
public string GetMergedText()
{
return string.Join(" ", Chunks.Select(c => c.Text));
}
public string ToDatabaseRow(int pageNumber)
{
return $"{pageNumber},\"{FontName}\",{FontSize},{Color},{Angle},{text_x},{text_y},{GetMergedText()}";
}
}
}// public class DxfSmartEngineeringTextGrouper : IEventListener
//saan has generated this seperately to get the text grouping strategy
public class DxfTextGroupingStrategy___Y_FIRST_THEN_X_NO_SLOPES : IEventListener
{
//we need the report of the text groups as column in a database insertable formats column names like (page wise font wise color wise thickness wise text style wise angle wise left to right baseline vector wise nearest broken texts are to merge as single text group)
private readonly List<TextChunk> chunks = new List<TextChunk>();
public void EventOccurred(IEventData data, EventType type)
{
if (type == EventType.RENDER_TEXT)
{
var renderInfo = (TextRenderInfo)data;
string text = renderInfo.GetText();
Vector start = renderInfo.GetBaseline().GetStartPoint();
Vector end = renderInfo.GetBaseline().GetEndPoint();
float angle = (float)Math.Atan2(end.Get(1) - start.Get(1), end.Get(0) - start.Get(0));
float dist = end.Subtract(start).Length();
float texts___x = start.Get(0);
float texts___y = start.Get(1);
//need the smarter calculations for the engineering documents cases
chunks.Add(new TextChunk
{
Text = text,
X = start.Get(0),
Y = start.Get(1),
Width = dist,
Angle = angle
});
}// if (type == EventType.RENDER_TEXT)
}// public void EventOccurred(IEventData data, EventType type)
public ICollection<EventType> GetSupportedEvents()
{
return new HashSet<EventType> { EventType.RENDER_TEXT };
}// public ICollection<EventType> GetSupportedEvents()
public List<string> GetMergedLines()
{
//need to sort with fontname first then with angle then X and the nearestnesst along the baseline vector is important to grab because Engineering PDF files have lots of slant texts groups
var sorted = chunks.OrderByDescending(c => c.Y).ThenBy(c => c.X).ToList();
var lines = new List<List<TextChunk>>();
float lineThreshold = 2.0f;
foreach (var chunk in sorted)
{
//Font style , Font name , Font color , Glyph weight slope baseline vector directions , nearness contiguity of chunks are important while clubbing and grouping the texts because these characteristics are crucial in engineering documents while clubbing togather to make the groups of texts chunks
var line = lines.FirstOrDefault(l => Math.Abs(l[0].Y - chunk.Y) < lineThreshold);
if (line == null)
{
line = new List<TextChunk>();
lines.Add(line);
}
line.Add(chunk);
}//foreach (var chunk in sorted)
var mergedLines = new List<string>();
foreach (var line in lines)
{
//this ordering is not sufficient for grouping the text in engineering documents because in Engineering documents texts are not on single Y values instead the angles , unit vectors of base lines sameness and nearestness (text width falls within threshold along the unitvector of base line) is more crucial to group togather the text chunks,
var ordered = line.OrderBy(c => c.X).ToList();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ordered.Count; i++)
{
if (i > 0)
{
float gap = ordered[i].X - (ordered[i - 1].X + ordered[i - 1].Width);
if (gap > 1.0f)
sb.Append(" ");
}
sb.Append(ordered[i].Text);
} // for (int i = 0; i < ordered.Count; i++)
mergedLines.Add(sb.ToString());
}//foreach (var line in lines)
return mergedLines;
}//public List<string> GetMergedLines()
public class TextChunk
{
public string Text;
public float X;
public float Y;
public float Width;
public float Angle;
public string StringFontName;//saan adds this
}//public class TextChunk
}// public class DxfTextGroupingStrategy___Y_FIRST_THEN_X_NO_SLOPES : IEventListener
/// <summary>
/// ////////////////////////////////////////////////////////////////////////////
/// </summary>
public class PdfGraphicsExtractor_to_singles_30000_offsets_dxf____trying_with_new_scales_translations
{
//calling convention PdfGraphicsExtractor_to_singles_30000_offsets_dxf____trying_with_new_scales_translations.shape_counter_in_this_page
public static int shape_counter_in_this_page = 0;
public static void publicstaticvoid___read_inputFilePath_dump_pagewise_graphics_data(string selected_pdffilesnames,ref System.Windows.Forms.ProgressBar refspbar,ref System.Windows.Forms.Label reflabelforpagereadingstatus)
{
StringBuilder ___STRBLDR_PAGE_WISE_LOCATIONS_WISE_TEXTGROUPING_DATA_WITH_TEXTGROUPS_STRATEGY = new StringBuilder();
___STRBLDR_PAGE_WISE_LOCATIONS_WISE_TEXTGROUPING_DATA_WITH_TEXTGROUPS_STRATEGY.Clear();
string inputFilePath = selected_pdffilesnames;
string outputFilePath = inputFilePath + "___dumping_pagewises_graphics_data.txt";
string dxfFilePath = inputFilePath + "___pagewises_graphics_data.dxf";
PdfReader reader = new PdfReader(inputFilePath);
PdfDocument pdfDoc = new PdfDocument(reader);
//////real important constructor which grabs the data really for the dxf generations
GraphicsAndText_ExtractionListener listener = new GraphicsAndText_ExtractionListener();//this does the real pdf contents graphics and texts extractions
// Create a PdfCanvasProcessor
PdfCanvasProcessor processor = new PdfCanvasProcessor(listener);
DxfTextGroupingStrategy___Y_FIRST_THEN_X_NO_SLOPES TextGrouping_strategy___WITH_Y_FIRST_THEN_X_NO_SLOPE_TAKEN_CARES = new DxfTextGroupingStrategy___Y_FIRST_THEN_X_NO_SLOPES();
PdfCanvasProcessor TextGroupingCanvas_processor_With_TextGroupingStrategy = new PdfCanvasProcessor(TextGrouping_strategy___WITH_Y_FIRST_THEN_X_NO_SLOPE_TAKEN_CARES);
DxfSmartEngineeringTextGrouper grouper = new DxfSmartEngineeringTextGrouper();
var processor___DxfSmartEngineeringTextGrouper = new PdfCanvasProcessor(grouper);
// processor___DxfSmartEngineeringTextGrouper.ProcessPageContent(doc.GetPage(i));
refspbar.Minimum = 0;
refspbar.Maximum = pdfDoc.GetNumberOfPages();
refspbar.Value = 0;
refspbar.Invalidate();
refspbar.Refresh();
StringBuilder ___pagewise_stringbuilder_returned = new StringBuilder();
___pagewise_stringbuilder_returned.Clear();
___pagewise_stringbuilder_returned
.AppendLine
(
"PageNumber\tGroupIndex\tSlopeInDegrees\tColor\tFontName\tFontHeight\tX\tY\tTextContent"
);
// Process each page
for (int i = 1; i <= pdfDoc.GetNumberOfPages(); i++)
{
reflabelforpagereadingstatus.Text = i + " of " + refspbar.Maximum;
reflabelforpagereadingstatus.Invalidate();
reflabelforpagereadingstatus.Refresh();
// refspbar.Minimum = 0;
// refspbar.Maximum = pdfDoc.GetNumberOfPages();
refspbar.Value = i;
refspbar.Invalidate();
refspbar.Refresh();
PdfPage page = pdfDoc.GetPage(i);
float pageWidth = page.GetPageSize().GetWidth();
float pageHeight = page.GetPageSize().GetHeight();
double doublepagewidth = (double)pageWidth;
double doublepageheight = (double)pageHeight;
PdfGraphicsExtractor_to_singles_30000_offsets_dxf____trying_with_new_scales_translations
.shape_counter_in_this_page = 0;
//this is called and after this we read the path data and text data
listener.SetPageInfo(i, pageWidth, pageHeight);//this stores the informations to the listener to do the processings
processor.ProcessPageContent(page);//this does the real working
/////////////////////////////////////////////////////////////////////
///
/// TextGroupingCanvas_processor_With_TextGroupingStrategy.ProcessPage(page);
TextGroupingCanvas_processor_With_TextGroupingStrategy.ProcessPageContent(page);
var lines = TextGrouping_strategy___WITH_Y_FIRST_THEN_X_NO_SLOPE_TAKEN_CARES.GetMergedLines();
int linecounterascountofgroupedtexts = 0;
foreach (var line in lines)
{
linecounterascountofgroupedtexts++;
// Console.WriteLine(line); // Replace with DXF text writer
___STRBLDR_PAGE_WISE_LOCATIONS_WISE_TEXTGROUPING_DATA_WITH_TEXTGROUPS_STRATEGY
.AppendLine();
___STRBLDR_PAGE_WISE_LOCATIONS_WISE_TEXTGROUPING_DATA_WITH_TEXTGROUPS_STRATEGY
.Append("\r\nPage "+ i + " ");
___STRBLDR_PAGE_WISE_LOCATIONS_WISE_TEXTGROUPING_DATA_WITH_TEXTGROUPS_STRATEGY
.Append( linecounterascountofgroupedtexts +" ");
___STRBLDR_PAGE_WISE_LOCATIONS_WISE_TEXTGROUPING_DATA_WITH_TEXTGROUPS_STRATEGY
.Append(line);
}//foreach (var line in lines)
//TOO MUCH SLOW processor___DxfSmartEngineeringTextGrouper.ProcessPageContent(pdfDoc.GetPage(i));
//TOO MUCH SLOW var grouped = grouper.GroupTextChunks();
//////DxfTextInserter. InsertTextGroupToDXF($"{inputFilePath}_output_page_{i}.dxf", grouped);
//////// Export TSV report
//////string tsvPath = $"{inputFilePath}___output_page_{i}_textgroups.tsv";
//////EngineeringTextGroupExporter.ExportTextGroupsToTsv(tsvPath, i, grouped);
///
//TOO MUCH SLOW
////// ___pagewise_stringbuilder_returned
////// .AppendLine
////// (
//////"\r\nPage "+i +"\r\n" +
////// EngineeringTextGroupExporter
////// .ExportTextGroupsToTsv___returns_stringbuilder___pagewises(i, grouped)
////// .ToString()
////// )
////// ;
}// for (int i = 1; i <= pdfDoc.GetNumberOfPages(); i++)
// Write the extracted graphics data to a file
listener.WriteGraphicsData(outputFilePath);
// Write the extracted graphics data to a DXF file
listener.WriteDxfData(dxfFilePath);
// Close the PdfDocument
pdfDoc.Close();
Console.WriteLine("Graphics extraction and DXF generation completed successfully.");
System.IO.File.WriteAllText
(
outputFilePath + "_GROUPED_TEXTS_REPORTS_PAGEWISE.txt"
,
___STRBLDR_PAGE_WISE_LOCATIONS_WISE_TEXTGROUPING_DATA_WITH_TEXTGROUPS_STRATEGY
.ToString()
);
//////////////////////////////////////////////////////////////////////////////////////////////////
System.IO.File.WriteAllText
(
outputFilePath + "_GROUPED_TEXTS_ENGINEERINGLY_TEXT_MERGED_PAGEWISE.txt"
,
___pagewise_stringbuilder_returned
.ToString()
);
// refspbar.Minimum = 0;
// refspbar.Maximum = pdfDoc.GetNumberOfPages();
refspbar.Value = refspbar.Maximum;
refspbar.Invalidate();
refspbar.Refresh();
System.Windows.Forms.MessageBox.Show("Graphics extraction and DXF generation completed successfully.");
}//public static void publicstaticvoid___read_inputFilePath_dump_pagewise_graphics_data(string selected_pdffilesnames)
//////public static void InsertTextGroupToDXF(string dxfPath,int pagenumber, List<DxfSmartEngineeringTextGrouper.TextGroup> textGroups)
//////{
////// using (var writer = new StreamWriter(dxfPath))
////// {
////// writer.WriteLine("0\nSECTION\n2\nENTITIES");
////// foreach (var group in textGroups)
////// {
////// foreach (var chunk in group.Chunks)
////// {
////// writer.WriteLine("0\nTEXT");
////// writer.WriteLine("8\n0");
////// writer.WriteLine($"10\n{chunk.X}\n20\n{chunk.Y}");
////// writer.WriteLine($"40\n{chunk.FontSize}");
////// writer.WriteLine($"1\n{chunk.Text}");
////// writer.WriteLine($"50\n{chunk.Angle * 180.0 / Math.PI}");
////// }
////// }
////// writer.WriteLine("0\nENDSEC\n0\nEOF");
////// }
//////}// public static void InsertTextGroupToDXF(string dxfPath,int pagenumber, List<DxfSmartEngineeringTextGrouper.TextGroup> textGroups)
}// public class PdfGraphicsExtractor_to_singles_30000_offsets_dxf____trying_with_new_scales_translations
public static class EngineeringTextGroupExporter
{
public static void ExportTextGroupsToTsv___TOO_MUCH_SLOW(string outputPath, int pageNumber, List<DxfSmartEngineeringTextGrouper.TextGroup> groups)
{
using (var writer = new StreamWriter(outputPath, false, Encoding.UTF8))
{
// Header
writer.WriteLine("PageNumber\tGroupIndex\tSlopeInDegrees\tColor\tFontName\tFontHeight\tX\tY\tTextContent");
int groupIndex = 0;
foreach (var group in groups)
{
// Assumes all chunks in the group have same font, angle, etc. (typical for engineering docs)
DxfSmartEngineeringTextGrouper.TextChunk___DxfSmartEngineeringTextGrouper firstChunk = group.Chunks.FirstOrDefault();
if (firstChunk == null)
{ continue; }
string slope = (firstChunk.Angle * 180.0 / Math.PI).ToString("F2");
string fontName = firstChunk.FontName ?? "Unknown";
string fontColor = firstChunk.Color.Replace("DETA7.Kernel.Colors.","") ?? "Default";
string fontHeight = firstChunk.FontSize.ToString("F2");
string mergedText = string.Join("", group.Chunks.Select(c => c.Text)).Replace("\t", " "); // Avoid tabs in text
float ___first_chunk_start_x = firstChunk.X;
float ___first_chunk_start_y = firstChunk.Y;
writer.WriteLine($"{pageNumber}\t{groupIndex}\t{slope}\t{fontColor}\t{fontName}\t{fontHeight}\t{___first_chunk_start_x}\t{___first_chunk_start_y}\t{mergedText}");
groupIndex++;
}
}
}// public static void ExportTextGroupsToTsv___TOO_MUCH_SLOW(string outputPath, int pageNumber, List<DxfSmartEngineeringTextGrouper.TextGroup> groups)
public static StringBuilder ExportTextGroupsToTsv___returns_stringbuilder___pagewises( int pageNumber, List<DxfSmartEngineeringTextGrouper.TextGroup> groups)
{
StringBuilder ___strbldr_pagewises = new StringBuilder();
___strbldr_pagewises.Clear();
// Header
// writer.WriteLine(c);
int groupIndex = 0;
foreach (var group in groups)
{
// Assumes all chunks in the group have same font, angle, etc. (typical for engineering docs)
DxfSmartEngineeringTextGrouper.TextChunk___DxfSmartEngineeringTextGrouper firstChunk = group.Chunks.FirstOrDefault();
if (firstChunk == null)
{ continue; }
string slope = (firstChunk.Angle * 180.0 / Math.PI).ToString("F2");
string fontName = firstChunk.FontName ?? "Unknown";
string fontColor = firstChunk.Color.Replace("DETA7.Kernel.Colors.", "") ?? "Default";
string fontHeight = firstChunk.FontSize.ToString("F2");
string mergedText = string.Join("", group.Chunks.Select(c => c.Text)).Replace("\t", " "); // Avoid tabs in text
float ___first_chunk_start_x = firstChunk.X;
float ___first_chunk_start_y = firstChunk.Y;
// writer.WriteLine($"{pageNumber}\t{groupIndex}\t{slope}\t{fontColor}\t{fontName}\t{fontHeight}\t{___first_chunk_start_x}\t{___first_chunk_start_y}\t{mergedText}");
___strbldr_pagewises
.AppendLine
(
$"{pageNumber}\t{groupIndex}\t{slope}\t{fontColor}\t{fontName}\t{fontHeight}\t{___first_chunk_start_x}\t{___first_chunk_start_y}\t{mergedText}"
);
groupIndex++;
}// foreach (var group in groups)
return ___strbldr_pagewises;
}// public static StringBuilder ExportTextGroupsToTsv___returns_stringbuilder___pagewises( int pageNumber, List<DxfSmartEngineeringTextGrouper.TextGroup> groups)
}// public static class EngineeringTextGroupExporter
public static class DxfTextInserter
{
public static void InsertTextGroupToDXF__________TOO_MUCH_SLOW(string dxfPath, List<DxfSmartEngineeringTextGrouper.TextGroup> textGroups)
{
using (var writer = new StreamWriter(dxfPath))
{
writer.WriteLine("0\nSECTION\n2\nENTITIES");
foreach (var group in textGroups)
{
foreach (var chunk in group.Chunks)
{
writer.WriteLine("0\nTEXT");
writer.WriteLine("8\n0");
writer.WriteLine($"10\n{chunk.X}\n20\n{chunk.Y}");
writer.WriteLine($"40\n{chunk.FontSize}");
writer.WriteLine($"1\n{chunk.Text}");
writer.WriteLine($"50\n{chunk.Angle * 180.0 / Math.PI}");
}
}
writer.WriteLine("0\nENDSEC\n0\nEOF");
}
}//public static void InsertTextGroupToDXF__________TOO_MUCH_SLOW(string dxfPath, List<DxfSmartEngineeringTextGrouper.TextGroup> textGroups)
}//public static class DxfTextInserter
}//namespace saan_trying_pathspositioningscaling_3000_OFFSETS_PAGES_TRANSFORMATIONS_MATRIX_GRAPHIKS_STATES_graphics_data_extractions_pagewises
Comments
Post a Comment