Hi there! I am converting a prototype (made using pymupdf to mupdf_net, and using the same commands (page.GetDrawings) and re-drawing using the same strategy in python and C#, I got different results… Anyone have any clue on how (or why) to solve this?
This is the python code:
“def draw_graphics_from(input_doc: pymupdf.Document, output_doc: pymupdf.Document) → pymupdf.Document:
\# page = input_doc\[0\]
outpdf = output_doc #pymupdf.open()
file_export = open('./assets/exported_paths_python.txt', 'w')
for page_num, page in enumerate(input_doc):
paths = page.get_drawings()
outpage = outpdf.load_page(page_num)
shape = outpage.new_shape()
percent = 0
print(f'Drawing {len(paths)} items on page {page_num + 1}: ', flush=True, end=' ')
for i, path in enumerate(paths):
\# if i % (len(paths) // 10) == 0 and i > 0:
\# percent += 10
\# print(f'{percent}%...', flush=True, end='')
for item in path\["items"\]: # these are the draw commands
if item\[0\] == "l": # line
shape.draw_line(item\[1\], item\[2\])
file_export.write(f'{i:03}\] line: {item\[0\]} >>> {item\[1\]}, {item\[2\]}\\n')
elif item\[0\] == "re": # rectangle
shape.draw_rect(item\[1\])
file_export.write(f'{i:03}\] rect: {item\[0\]} >>> {item\[1\]}\\n')
elif item\[0\] == "qu": # quad
shape.draw_quad(item\[1\])
file_export.write(f'{i:03}\] quad: {item\[0\]} >>> {item\[1\]}\\n')
elif item\[0\] == "c": # curve
shape.draw_bezier(item\[1\], item\[2\], item\[3\], item\[4\])
file_export.write(f'{i:03}\] curve: {item\[0\]} >>> {item\[1\]}, {item\[2\]}, {item\[3\]}, {item\[4\]}\\n')
else:
raise ValueError("unhandled drawing", item)
lwidth = path.get("width", 0.03)
if type(lwidth) is not float:
lwidth = float(DEFAUL_LINE_WIDTH)
if lwidth <= 0.03:
lwidth = float(DEFAUL_LINE_WIDTH)
\# print(f'Path width: {lwidth}, type: {type(lwidth)}', flush=True)
shape.finish(
fill=path\["fill"\], # fill color
color = (random.random(), random.random(), random.random()) if USE_RANDOM_COLORS else DEFAULT_COLOR, #path\["color"\], # line color
dashes=path\["dashes"\], # line dashing
even_odd=path.get("even_odd", True), # control color of overlaps
closePath=path\["closePath"\], # whether to connect last and first point
lineJoin= 1, #max(path.get("lineJoin", 0), 1), # how line joins should look like
lineCap = 1, #(1, 1, 1), # max(path.get("lineCap", 1)), # how line ends should look like
width = lwidth, # line_width, # path\["width"\], # line width
stroke_opacity= 1, # path.get("stroke_opacity", 1.0), # same value for both
fill_opacity= 1, #path.get("fill_opacity", 1.0), # opacity parameters
)
file_export.write(f'Path {i:03}\] width: {lwidth}, dashes: {path\["dashes"\]}, closePath: {path\["closePath"\]}\\n')
print('Done.', flush=True)
shape.commit()
file_export.close()
return outpdf“
And this is the C# code:
“ public Document? draw_graphics_from(Document inputDoc, Document outputDoc, float newWidth, IProgress progress)
{
string filePath = @"D:\\Vectorlab\\Jobs\\2025\\PACE\\pdf_fix\\assets\\exported_paths_net.txt";
StreamWriter writer = new StreamWriter(filePath);
if (inputDoc.PageCount != outputDoc.PageCount)
{
return null;
}
for (int pagNum = 0; pagNum < inputDoc.PageCount; pagNum++)
{
Page page = inputDoc.LoadPage(pagNum);
Page outPage = outputDoc.LoadPage(pagNum);
List<PathInfo> paths = page.GetDrawings(extended: false);
int totalPaths = paths.Count;
Shape shape = outPage.NewShape();
int i = 0;
progress.Report(0);
foreach (PathInfo pathInfo in paths)
{
foreach (Item item in pathInfo.Items)
{
if (item != null)
{
if (item.Type == "l")
{
shape.DrawLine(item.P1, item.LastPoint);
writer.Write($"{i:000}\] line: {item.Type} >>> {item.P1}, {item.LastPoint}\\n");
}
else if (item.Type == "re")
{
shape.DrawRect(item.Rect, item.Orientation);
writer.Write($"{i:000}\] rect: {item.Type} >>> {item.Rect}, {item.Orientation}\\n");
}
else if(item.Type == "qu")
{
shape.DrawQuad(item.Quad);
writer.Write($"{i:000}\] quad: {item.Type} >>> {item.Quad}\\n");
}
else if(item.Type == "c")
{
shape.DrawBezier(item.P1, item.P2, item.P3, item.LastPoint);
writer.Write($"{i:000}\] curve: {item.Type} >>> {item.P1}, {item.P2}, {item.P3}, {item.LastPoint}\\n");
}
else
{
throw new Exception("unhandled drawing. Aborting...");
}
}
}
//pathInfo.Items.get
float newLineWidth = pathInfo.Width;
if (pathInfo.Width <= newWidth)
{
newLineWidth = newWidth;
}
shape.Finish(
fill: pathInfo.Fill,
color: pathInfo.Color, //this.\_m_DEFAULT_COLOR,
dashes: pathInfo.Dashes,
evenOdd: true, //pathInfo.EvenOdd,
closePath: pathInfo.ClosePath,
lineJoin: (int)1,
lineCap: (int)1,
width: newLineWidth,
strokeOpacity: (int)pathInfo.StrokeOpacity,
fillOpacity: (int)pathInfo.FillOpacity
);
double progressValue = ((double)i / (double)totalPaths) \* 100.0;
progress.Report((int)progressValue);
// file_export.write(f'Path {i:03}\] width: {lwidth}, dashes: {path\["dashes"\]}, closePath: {path\["closePath"\]}\\n')
writer.Write($"Path {i:000}\] with: {newLineWidth}, dashes: {pathInfo.Dashes}, closePath: {pathInfo.ClosePath}\\n");
i++;
}
shape.Commit();
}
writer.Close();
return outputDoc;
}“
And the image above is the results
