We have recently added support for inserting and retrieving images from headers and footers section of an Excel spreadsheet. To enable this, we needed to parse the HFPicture records, which turned out to be a difficult task, especially due to lacking documentation.
When a user adds a picture to a worksheet header or footer section, there is no change to the HEADER or FOOTER records (except for the addition of the &G or &[Picture] tokens to the text). So how are the pictures added to file, and how are they linked to the specific header or footer section?
Let’s start by examining the HFPicture record – we will find that, oddly enough, the HFPicture record is simply a wrapper around the DGContainer or the DGGContainer. Which of these it is is determined by the HFPicture’s fIsDrawing and fIsDrawingGroup bits, and if this HFPicture record is a continuation of a previous HFPicture (due to the size limit of the records), the bit fContinue will also be set. Therefore, an image in a header/footer section will be represented very much like regular images.
Two HFPictures will be created:
1. The first is in the worksheet stream (as well as in the other type of sheet steam, such as chartsheet stream) as the MSODrawing, which has some properties like the blip id.
2. The second is representing the MSODrawingGroup in the global stream of the workbook, where the actual data (the blips) of all the headers/footers pictures will be stored, referenced by their blip id.
So we make the HFPicture class as a wrapper around the Drawing and DrawingGroup classes. That way all the logic we already have in place for parsing, creating and writing is used for the HFPicture class. Since HFPicture can represent either MSODrawing or MSODrawingGroup, we need to tweak the code to first check which type it is, then create the inner element as either a drawing element or a drawing group element, and pass along any continuations we find.
Now comes the time to find out how a specific image in an HFPicture is linked to a specific header or footer section. As we couldn’t find any documentation regarding this, figuring it out required some poking around… It turns out the link is done through the wzName property (also referred to as the shape name) in the OfficeArtFOPT record in the drawing element of the HFPicture in the worksheet stream, thus it‘s specific to each worksheet. To link an image to a specific header/footer and section, the wzName is made of two letters, the first indicating the section – L for left, C for center and R for right–followed by the letter indicating the header or footer – H or F respectively. So if the wzName is CH, this image will appear in the center header; if it is LF it will appear in the left footer. Setting this property will cause the image to appear in the correct section; not setting it will mean the picture won’t show at all.
One last peculiarity that takes some working around is the ClientAnchorHF record. This record is part of the MSODrawing element, but when this image refers to a header/footer image, the regular anchor type – OfficeArtClientAnchor – is, underneath the hood, a ClientAnchorHF. Therefore, while these records share the same type (0xF010) as the other types of anchors, they have a completely different structure and require a separate handling. Please note that the height and width set here (which can be used to modify the height and width of the image) are in pixels not points or twips.
Share the post "Excel Binary HFPicture Record: Parsing Pictures in Headers and Footers"