Ваше изображение показывает, что вы хотите редактировать заглавные и строчные строки во всех путях, чтобы они были круглыми.
К сожалению, вы не предоставили доступ к типичным файлам примеров, поэтому мне пришлось создавать их самостоятельно, используя смесь различныхстили cap и join и форма пути, напоминающая ваш:
Я бы предложил для вашей задачи использовать общий PdfContentStreamEditor
из этот ответ , поскольку он выполняет всю тяжелую работу, и мы можем сосредоточиться на поставленной задаче.
Итак, что должна делать наша реализация редактора потоков?Он должен установить cap и join style на "round" и предотвратить переопределение этих настроек.Изучив спецификацию PDF, мы увидим, что стили cap и join являются параметрами текущего графического состояния и могут быть установлены напрямую с помощью инструкций J и j соответственно или с помощью Записи LC и LJ в Словаре параметров состояния графики.
Таким образом, мы можем реализовать наш редактор потоков, просто инициализировав cap и стиль соединения для round, а затем отбросив все J и j инструкции и повторно инициализировать cap и стили соединения после каждого графического состояния gs инструкция.
class PathMakeCapAndJoinRound : PdfContentStreamEditor
{
protected override void Write(PdfContentStreamProcessor processor, PdfLiteral operatorLit, List<PdfObject> operands)
{
if (start)
{
initializeCapAndJoin(processor);
start = false;
}
if (CAP_AND_JOIN_OPERATORS.Contains(operatorLit.ToString()))
{
return;
}
base.Write(processor, operatorLit, operands);
if (GSTATE_OPERATOR == operatorLit.ToString())
{
initializeCapAndJoin(processor);
}
}
void initializeCapAndJoin(PdfContentStreamProcessor processor)
{
PdfLiteral operatorLit = new PdfLiteral("J");
List<PdfObject> operands = new List<PdfObject> { new PdfNumber(PdfContentByte.LINE_CAP_ROUND), operatorLit };
base.Write(processor, operatorLit, operands);
operatorLit = new PdfLiteral("j");
operands = new List<PdfObject> { new PdfNumber(PdfContentByte.LINE_JOIN_ROUND), operatorLit };
base.Write(processor, operatorLit, operands);
}
List<string> CAP_AND_JOIN_OPERATORS = new List<string> { "j", "J" };
string GSTATE_OPERATOR = "gs";
bool start = true;
}
Применяя его таким образом кPDF выше
using (PdfReader pdfReader = new PdfReader(testDocument))
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(@"Paths-Rounded.pdf", FileMode.Create, FileAccess.Write), (char)0, true))
{
pdfStamper.RotateContents = false;
PdfContentStreamEditor editor = new PathMakeCapAndJoinRound();
for (int i = 1; i <= pdfReader.NumberOfPages; i++)
{
editor.EditPage(pdfStamper, i);
}
}
мы получаем результат:
Осторожно, ограничения из ссылочного ответа остаются.В частности, этот редактор редактирует только поток содержимого страницы.Чтобы получить полное решение, вы также должны отредактировать все потоки форм XObject и Pattern, а также обработать аннотации.
Чтобы разрешить воспроизведение, я создал свой тестовый документ так:
byte[] createMixedPathsPdf()
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (Document document = new Document())
{
PdfWriter writer = PdfWriter.GetInstance(document, memoryStream);
document.Open();
var canvas = writer.DirectContent;
canvas.SetLineWidth(10);
canvas.MoveTo(100, 700);
canvas.CurveTo(180, 720, 180, 720, 200, 800);
canvas.CurveTo(220, 720, 220, 720, 350, 700);
canvas.MoveTo(350, 700);
canvas.CurveTo(220, 680, 220, 680, 210, 650);
canvas.Stroke();
canvas.SetLineCap(PdfContentByte.LINE_CAP_BUTT);
canvas.SetLineJoin(PdfContentByte.LINE_JOIN_BEVEL);
canvas.SetGState(createGState(PdfContentByte.LINE_CAP_BUTT, PdfContentByte.LINE_JOIN_BEVEL));
canvas.MoveTo(100, 500);
canvas.CurveTo(180, 520, 180, 520, 200, 600);
canvas.CurveTo(220, 520, 220, 520, 350, 500);
canvas.MoveTo(350, 500);
canvas.CurveTo(220, 480, 220, 480, 210, 450);
canvas.Stroke();
canvas.SetLineCap(PdfContentByte.LINE_CAP_PROJECTING_SQUARE);
canvas.SetLineJoin(PdfContentByte.LINE_JOIN_MITER);
canvas.SetGState(createGState(PdfContentByte.LINE_CAP_PROJECTING_SQUARE, PdfContentByte.LINE_JOIN_MITER));
canvas.MoveTo(100, 300);
canvas.CurveTo(180, 320, 180, 320, 200, 400);
canvas.CurveTo(220, 320, 220, 320, 350, 300);
canvas.MoveTo(350, 300);
canvas.CurveTo(220, 280, 220, 280, 210, 250);
canvas.Stroke();
canvas.SetLineCap(PdfContentByte.LINE_CAP_ROUND);
canvas.SetLineJoin(PdfContentByte.LINE_JOIN_ROUND);
canvas.SetGState(createGState(PdfContentByte.LINE_CAP_ROUND, PdfContentByte.LINE_JOIN_ROUND));
canvas.MoveTo(100, 100);
canvas.CurveTo(180, 120, 180, 120, 200, 200);
canvas.CurveTo(220, 120, 220, 120, 350, 100);
canvas.MoveTo(350, 100);
canvas.CurveTo(220, 080, 220, 080, 210, 050);
canvas.Stroke();
}
return memoryStream.ToArray();
}
}
PdfGState createGState(int lineCap, int lineJoin)
{
PdfGState pdfGState = new PdfGState();
pdfGState.Put(new PdfName("LC"), new PdfNumber(lineCap));
pdfGState.Put(new PdfName("LJ"), new PdfNumber(lineJoin));
return pdfGState;
}