DEV Community

loading...

Hacking Together A PDF To Image Export Library

herocod3r profile image Jethro Daniel ・3 min read

So, the other day at work, i got a ticket to build a feature to export pdf documents as images. It looked like a straight forward task, but quickly turned out to be a nightmare.

The Problem

Many of the PDF spec implementations in circulation today are always almost natively written (C/C++), and many languages all have a wrapper around them, because why re-invent the wheel when there is already a battle tested library right ?

Well, in my case this wasn't helpful, due to some dependency management/server constraints, i was unable to work with these types of implementations.

Solution 1: Get A Library

Since the native way wasnt feasible, i began heavy googling and research, trying to find 100% managed Go libraries, and yea, i found alot of libraries 100% go, but all of them didnt have the feature i really needed, which was exporting the pdf to image, at this point my brain was already experiencing a stackoverflow 🤯

Solution 2: Find A Managed Library In Another Language

Simply write that part of our system in another language, that had managed libraries to work with, surely enough i got many libraries like that are in C#/Java etc to work with, which is good since i have significant experience in C#. But at this point my paranoia was off the charts, simply accepting a solution like this was not satisfactory to me.

Solution 3: Building My Own Library In A Managed Language

So how hard would it be implementing a pdf to image library in a managed language ? 😏

Well, turns out that it is not so difficult. I started of my journey by understanding what exactly is truly involved, went to github, to look for some ideas, i saw a project with a proof of concept, and basically all they did was to take the PDF document, parse it and extract the pdf objects (images/text) and draw them onto a canvas and save the canvas as an image.

This should be fun i thought, i started writing my own implementation, and in under a day working with C#/.Net Core and its beautiful low level APIs, and this beautiful library ImageSharp i was able to hack something together.

Soon enough all the pdf hidden Spec features began to hunt me, Pdfs with images that had opacity were a nightmare, pdfs with custom fonts also came along and on and on, any new pdf i tried, came with its own twist.

Final Solution

I soon realised that this is another whole project on its own, and since time was running out i decided to fallback to Solution 2 and quickly close the ticket.

Then another roadblock, the perfect library i found in Solution 2 was exporting the image in ARGB32 pixel format, essentially when i try to parse the image i get images in this all blue format, like a snapchat filter.

Thanks to the knowledge learnt in Solution 3, i was able to manipulate the raw bytes of the image and fix the exported image by manipulating the individual pixel. Rearranging them back to RGBA32 pixel format.

Span<byte> imgBytes = reader.GetImage(new NaiveTransparencyRemover(255, 255, 255));

var width = reader.GetPageWidth();
var height = reader.GetPageHeight();

var newImage = new Image<Rgba32>(width,height);
var rowBytes = width * 4;
for (int i = 0; i < imgBytes.Length; i+=rowBytes)
{
     var singleRow = imgBytes.Slice(i, rowBytes);
     Span<Rgba32> pixelRowSpan = newImage.GetPixelRowSpan(i == 0?0:i/rowBytes);
     for (int j = 0; j < rowBytes; j+=4)
     {
         var px = singleRow.Slice(j, 4);
          pixelRowSpan[j==0?0:j/4] = new Rgba32(px[2],px[1],px[0],px[3]);
      }
 }


using (var fs = File.Create(Path.Combine(Environment.CurrentDirectory, $"wave-{DateTime.Now.Ticks}.png")))
{
        newImage.SaveAsPng(fs);
}

Enter fullscreen mode Exit fullscreen mode

Summary

This was an interesting ticket to work on, i learnt alot about computer graphics, pixel standards, the PDF specification and all, i hope i can comeback and work on a 100% easy managed solution in Go as a side project.

Discussion (0)

pic
Editor guide