Search code examples
c#.netabcpdf

How to add an image into a spot colour channel for a PDF document using ABCpdf?


While using ABCpdf programmatically, I found the need to add a new image into a specific custom colour channel (known as spot colours) in a PDF file. Usually these type of channels are used in the printing industry to add specialty colours such as gold, silver, etc onto the printed material and instructs the printing machine to use special inks during the process. Each spot colour channel can contain only 1 colour (with varying intensities based on their alpha value).

The problem comes with figuring out how to do that easily using ABCpdf. While the documentation does have a sample code for this using the AddColorSpaceSpot function in combination with the AddText function, there is no indication on how to accomplish this using an image. Any attempt at replacing AddText with AddImage is futile as it only adds the image as a normal RGB or CMYK object.

The sample code from the documentation reads:

Doc theDoc = new Doc();
theDoc.Rect.Inset(20, 20);
theDoc.FontSize = 300;
theDoc.ColorSpace = theDoc.AddColorSpaceSpot("GOLD", "0 0 100 0");
for (int i = 1; i <= 10; i++) {
  theDoc.Color.Gray = 255 / i;
  theDoc.AddText(theDoc.Color.Gray.ToString());
  theDoc.Rect.Move(25, -50);
}
theDoc.Save(Server.MapPath("docaddcolorspacespot.pdf"));
theDoc.Clear();

Based on the above code I tried the following in a console app:

Doc theDoc = new Doc();
theDoc.Rect.Inset(10, 10);
theDoc.ColorSpace = theDoc.AddColorSpaceSpot("Gold", "0 0 100 0");
theDoc.FontSize = 300;
theDoc.Color.Gray = 255;
theDoc.AddText("My Text");
theDoc.Save($"output/spot_test_{DateTime.Now.ToString("yyyyMMdd_HHmmss")}.pdf");
theDoc.Clear();

All works well up to now, the text "My Text" is present in the output PDF file in the correct "Gold" channel that was added.

So I replace the line theDoc.AddText("My Text"); with theDoc.AddImage("images/gradient_alpha.png")' expecting it to add this image into the current colour space that I created, but it didn't work.

Manually creating a new colour space, image object and pixmap object did not work either:

Doc theDoc = new Doc();

var cs = new ColorSpace(theDoc.ObjectSoup, ColorSpaceType.Separation);
cs.Doc.Color.String = "0 0 100 0";
cs.Doc.Color.Name = "Gold";
theDoc.ColorSpace = cs.ID;

var image = new XImage();
image.SetFile("images/gradient_alpha.png");
PixMap px = PixMap.FromXImage(theDoc.ObjectSoup, image);
px.Recolor(cs);

theDoc.AddImage(px.GetBitmap());

So, how do we correctly add an image into a spot colour channel? Read the answer below to find out!


Solution

  • To accomplish this, you need to add the image as an object into the document via AddImageObject and extract it as a PixMap from the document's ObjectSoup container and apply a Recolor on the PixMap with the destination colour space.

    Here is the final code that I managed to use successfully:

    Doc theDoc = new Doc();
    theDoc.ColorSpace = theDoc.AddColorSpaceSpot("Gold", "0 0 100 0");
    ColorSpace goldSpotColor = (ColorSpace)theDoc.ObjectSoup[theDoc.ColorSpace];
    
    XImage image = XImage.FromFile("images/gradient_alpha.png", new XReadOptions());
    
    int theID = theDoc.AddImageObject(image, true);
    int imageID = theDoc.GetInfoInt(theID, "XObject");
    PixMap thePM = (PixMap)theDoc.ObjectSoup[imageID];
    
    thePM.Recolor(goldSpotColor);
    
    theDoc.Save($"output/spot_test_{DateTime.Now.ToString("yyyyMMdd_HHmmss")}.pdf");
    theDoc.Clear();
    

    At first sight, it seems way too much steps to take for achieving what we want but ABCpdf is a low-level PDF manipulation library that is very powerful. The documentation is extensive but not always explicit so a lot of reading and experimentation is expected.