How can I enlarge the thin, zero-width lines of a PDF?

43 views
Skip to first unread message

Aaron

unread,
Apr 8, 2020, 4:51:45 PM4/8/20
to PDFTron PDFNet SDK
Q:

Some documents, such as CAD files, can have lots of very thin lines in them. Oftentimes, this is caused by zero-width lines, which my users can find hard to see even when zoomed in. Is there any way to make lines larger, so that they're easier to read?

A:

The following C# code can be used to expand the line widths of paths, as well as characters of Type3 fonts:

//
// Copyright (c) 2001-2020 by PDFTron Systems Inc. All Rights Reserved.
//

using System;
using System.Collections.Generic;

using pdftron;
using pdftron.Common;
using pdftron.Filters;
using pdftron.SDF;
using pdftron.PDF;

using XSet = System.Collections.Generic.List<int>;
using EltCase = System.Action<pdftron.PDF.ElementReader, pdftron.PDF.ElementWriter, pdftron.PDF.Element>;

namespace ElementEditTestCS
{
  class Class1
  {
    private static pdftron.PDFNetLoader pdfNetLoader = pdftron.PDFNetLoader.Instance();
    static Class1() {}

    static void ProcessElements(ElementReader reader, ElementWriter writer, XSet visited, 
                                EltCase path, EltCase text, EltCase form)
    {
      Element element;
      while ((element = reader.Next()) != null)
      {
        switch (element.GetType())
        {
          case Element.Type.e_path:
            path(reader, writer, element);
            break;
          case Element.Type.e_text:
            text(reader, writer, element);
            break;
          case Element.Type.e_form:
            {
              writer.WriteElement(element);
              Obj form_obj = element.GetXObject();
              if (!visited.Contains(form_obj.GetObjNum()))
              {
                visited.Add(form_obj.GetObjNum());
                ElementWriter new_writer = new ElementWriter();
                reader.FormBegin();
                new_writer.Begin(form_obj, true);
                reader.ClearChangeList();
                new_writer.SetDefaultGState(reader);
                form(reader, writer, element);
                new_writer.End();
                reader.End();
              }
              break;
            }
          default:
            writer.WriteElement(element);
            break;
        }
      }
    }

    static EltCase EnlargeZeroWidthLines(int new_width)
    {
      return (reader, writer, element) =>
        {
          GState gs = element.GetGState();
          if (gs.GetLineWidth() < 0.001) gs.SetLineWidth(new_width);
          writer.WriteElement(element);
        };
    }

    static void EnlargeCharacters(ElementReader reader_, ElementWriter writer_, XSet visited_)
    {
      ProcessElements(reader_, writer_, visited_, 
        EnlargeZeroWidthLines(10), // make zero-width lines in characters 10 units wide (better appearance)
        (reader, writer, element) => { writer.WriteElement(element); },
        (reader, writer, element) => { EnlargeCharacters(reader, writer, visited_); });
    }

    static void RewriteCharacters(PDFDoc doc, XSet charprocs)
    {
      ElementWriter writer = new ElementWriter();
      ElementReader reader = new ElementReader();
      XSet visited = new XSet();

      foreach (int charproc in charprocs)
      {
        SDFDoc sdf = doc.GetSDFDoc();
        reader.Begin(sdf.GetObj(charproc));
        writer.Begin(sdf);
        EnlargeCharacters(reader, writer, visited);
        reader.End();
        sdf.Swap(charproc, writer.End().GetObjNum());
      }
    }

    static XSet EnlargePaths(ElementReader reader_, ElementWriter writer_, XSet visited_)
    {
      XSet charprocs = new XSet();
      ProcessElements(reader_, writer_, visited_, 
        EnlargeZeroWidthLines(1), // make zero-width paths one unit wide
        (reader, writer, element) =>
          {
            writer.WriteElement(element);
            Obj font_dict = element.GetGState().GetFont().GetSDFObj();
            if (font_dict.Get("Subtype").Value().GetName() != "Type3") return;
            DictIterator itr = font_dict.Get("CharProcs").Value().GetDictIterator();
            while (itr.HasNext())
            {
              int n = itr.Value().GetObjNum();
              if (!charprocs.Contains(n)) charprocs.Add(n);
              itr.Next();
            }
          },
        (reader, writer, element) => { charprocs.AddRange(EnlargePaths(reader, writer, visited_)); });
      return charprocs;
    }

    static XSet RewritePages(PDFDoc doc)
    {
      ElementWriter writer = new ElementWriter();
      ElementReader reader = new ElementReader();
      XSet visited = new XSet();
      XSet charprocs = new XSet();

      PageIterator itr = doc.GetPageIterator();
      while (itr.HasNext())
      {
        Page page = itr.Current();
        visited.Add(page.GetSDFObj().GetObjNum());
        reader.Begin(page);
        writer.Begin(page, ElementWriter.WriteMode.e_replacement, false, true, page.GetResourceDict());
        charprocs.AddRange(EnlargePaths(reader, writer, visited));
        writer.End();
        reader.End();
        itr.Next();
      }

      return charprocs; // all type3 font characters (each might contain zero-width lines)
    }

    [STAThread]
    static void Main(string[] args)
    {
      PDFNet.Initialize();

      string input_path = "../../TestFiles/";
      string output_path = "../../TestFiles/Output/";
      string input_filename = //.....
      string output_filename = //.....

      try
      {
        Console.WriteLine("Opening the input file...");
        using (PDFDoc doc = new PDFDoc(input_path + input_filename))
        {
          doc.InitSecurityHandler();
          XSet charprocs = RewritePages(doc);
          RewriteCharacters(doc, charprocs);
          doc.Save(output_path + output_filename, SDFDoc.SaveOptions.e_remove_unused);
          Console.WriteLine("Done. Result saved in {0}...", output_filename);
        }
      }
      catch (PDFNetException e)
      {
        Console.WriteLine(e.Message);
      }
    }
  }
}




Reply all
Reply to author
Forward
0 new messages