Editing color space and other properties on an existing PDF page.

Q: I need to edit color space and other graphics state properies on
elements on an existing PDF page ( I want to convert a color PDF to
grayscale or separations, etc) .

I used ElementEdit sample project as a starting point (http://
www.pdftron.com/pdfnet/samplecode.html) and things are going great so
far, however I noticed that when I modify a color space and fill color
on some elements (see below for sample code) the change affects
subsequent elements from the input PDF page.

I would like to modify a color space or some other property, but I
don't want that this chnage affects subsequent elements.

// My C++ sample code ....

PDFNet::Initialize();

PDFDoc doc("original.pdf");
doc.InitSecurityHandler();

int num_pages = doc.GetPageCount();
ElementWriter writer;
ElementReader reader;
Element element;

for(int i=1; i<=num_pages; ++i)
{
  PageIterator itr = doc.GetPageIterator(i);
  Page page = itr.Current();
  reader.Begin(page);

  Page new_page = doc.PageCreate();
  PageIterator next_page = itr;
  next_page.Next();
  doc.PageInsert(next_page, new_page );

  writer.Begin(new_page);
  while (element = reader.Next()) // Read page contents
  {
    // README
    // The first and second element test is DeviceN but when load the
second this return DeviceGray (wrong)
    // the first value color is 0.1 and the second is 0.3
    // the problem is when you load the second value, the system return
DeviceGray and not need convert value
    // but this wrong because the value is on DeviceN y not on
DeviceGray and you see the object inverted
    // because the DeviceGray black is 0 and white is 1 but on DeviceN
black is 1 and white is 0
    if (element.GetType() == Element::e_path)
    {
      // Set all text to blue color.
      GState gs = element.GetGState();
      ColorSpace cs =
        gs.GetFillColorSpace();
      ColorPt color = gs.GetFillColor();
      if(cs.GetType() ==
        ColorSpace::e_device_n)
      {

        gs.SetFillColorSpace(ColorSpace::CreateDeviceGray());
        ColorPt colorout;

        cs.Convert2Gray(color,colorout);
        gs.SetFillColor(colorout);
      }
    }
    else if (element.GetType() == Element::e_image) {
      continue;// remove all images
    }

    writer.WriteElement(element);
  }

  writer.End();
  reader.End();
  new_page.SetMediaBox(page.GetCropBox());
  doc.PageRemove(doc.GetPageIterator(i));
}

doc.Save("edited.pdf", 0 , 0);
}
catch(Common::Exception& e) {
  cout << e << endl;
}
catch(...) {
  cout << "Unknown Exception" << endl;
}
-----------
A: In PDF, a change to the graphics state does not affect only a
single element, but all subsequent elements (until this property is
reset again).

What you need to do is to copy the graphics state, then reset it after
writing out the modified element. This way the state in the next
element will not be affected.

So, for your code (above) simply reset the color space and color to
old values after outputting the modified element...

// C++ pseudocode...
ColorSpace cs = gs.GetFillColorSpace();
ColorPt color = gs.GetFillColor();

if(cs.GetType() == ColorSpace::e_device_n) {
gs.SetFillColorSpace(ColorSpace::CreateDeviceGray());
ColorPt colorout;
cs.Convert2Gray(color,colorout);
gs.SetFillColor(colorout);
}

writer.WriteElement(element);

// Reset old values...
gs.SetFillColorSpace(cs);
gs.SetFillColor(color);

... read next element