Skip to content

Hacker’s Corner: How Big Is That Picture?

Vector 15:1, page 128

graphics system interfaces programming techniques

Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 128

The Problem

People have been badgering me for some time to add support for Windows metafiles to RainPro and NewLeaf - very handy for company logos or fancy graded fills in true PowerPoint style. I made the mistake of getting cornered at Rome, and compounded the error by saying how simple it would be to put this stuff in. Then I discovered one minor problem - most modern metafiles have a ‘placeable header’ which gives the designed size of the image; Dyalog lets you set this property for images which you generate, but always reports (0 0) as the ‘RealSize’ of files which already exist. Hmmm.

The Documentation

Here is what is says in the Windows SDK help file:

A placeable Windows metafile is a standard Windows metafile that has an additional 22-byte header. The header contains information about the aspect ratio and original size of the metafile, permitting applications to display the metafile in its intended form.

The header for a placeable Windows metafile has the following form:

typedef struct {
    DWORD   key;
    HANDLE  hmf;
    RECT    bbox;
    WORD    inch;
    DWORD   reserved;
    WORD    checksum;
} METAFILEHEADER;

Following are the members of a placeable metafile header:

key Specifies the binary key that uniquely identifies this file type. This member must be set to 0x9AC6CDD7L.
hmf Unused; must be zero.
bbox Specifies the coordinates of the smallest rectangle that encloses the picture. The coordinates are in metafile units as defined by the inch member.
inch Specifies the number of metafile units to the inch. To avoid numeric overflow, this value should be less than 1440. Most applications use 576 or 1000.
reserved Unused; must be zero.
checksum Specifies the checksum.

Clear as mud, really. We can make a few wild guesses about that ‘bbox’ data type, so let’s take the usual APL approach, read the first 22 bytes of the file as integers and just flail around until the numbers look sensible!

The Implementation

The objective was to make a function which takes the name of a metafile, detects the placeable header and returns the size in (x,y) co-ordinates to the nearest 1/10th of a point (1 point = 1/72 of an inch). Here is the final version:

    ∇ r←metasize file;magic;hdr;tn;inch
[1]   ⍝ Find the size of a placeable WMF from the 22-byte header
[2]   ⍝ Returns size in points (to nearest 1/10th point)
[3]   ⍝ If there is no placeable header, just return 1" square.
[4]    r←72 72 ⋄ magic←'9AC6CDD7' ⋄ tn←¯1+⌊/0,⎕NNUMS
[5]    file,←(~'.'∊file)/'.wmf'
[6]    file ⎕NTIE tn
[7]    hdr←⎕NREAD tn 83 22 0
[8]    ⎕NUNTIE tn
[9]   ⍝ Convert to unsigned ...
[10]   ((hdr<0)/hdr)←(hdr<0)/256+hdr
[11]  ⍝ Check against the magic word ...
[12]   :If magic∧.=,⍉⌽'0123456789ABCDEF'[1+16 16⊤4↑hdr]
[13]       inch←256⊥⌽2↑14↓hdr  ⍝ Generally 1000
[14]       r←256⊥⍉⌽4 2⍴8↑6↓hdr ⍝ Remember the flip (words reversed)
[15]       r←-⌿⊖2 2⍴r
[16]     ⍝ Fix wraparound at 2*16 ...
[17]       ((r<0)/r)←(r<0)/(2*16)+r
[18]       r←0.1×⌊0.5+720×r÷inch
[19]   :End
    ∇

The only nasty trip wires are addressed by line [10] and line [17] which handle the wraparound and return unsigned values. Other than this, it is simple and reliable, but do remember all those ‘reverse’ symbols to get your egg big-end up!