@Chris
I've written a simple wrapper (UNFINISHED - DO NOT USE!) for PortablE, but I have found that OFTEN (not always) the results are horizontally off-set by 1 pixel compared to the real BitMapScale():
PROC bitMapScale(bitScaleArgs:PTR TO bitscaleargs)
    DEF result
    result := CompositeTagList(COMPOSITE_SRC, bitScaleArgs.srcbitmap, bitScaleArgs.destbitmap, [
        COMPTAG_SRCX,      bitScaleArgs.srcx,
        COMPTAG_SRCY,      bitScaleArgs.srcy,
        COMPTAG_SRCWIDTH,  bitScaleArgs.srcwidth,
        COMPTAG_SRCHEIGHT, bitScaleArgs.srcheight,
        COMPTAG_DESTX,     bitScaleArgs.destx,
        COMPTAG_DESTY,     bitScaleArgs.desty,
        COMPTAG_DESTWIDTH, bitScaleArgs.destwidth,
        COMPTAG_DESTHEIGHT,bitScaleArgs.destheight,
        COMPTAG_OFFSETX,   bitScaleArgs.destx,
        COMPTAG_OFFSETY,   bitScaleArgs.desty,
        COMPTAG_SCALEX, bitScaleArgs.xdestfactor * COMP_FIX_ONE / bitScaleArgs.xsrcfactor,
        COMPTAG_SCALEY, bitScaleArgs.ydestfactor * COMP_FIX_ONE / bitScaleArgs.ysrcfactor,
OAT / bitScaleArgs.ysrcfactor),
        COMPTAG_FLAGS,COMPFLAG_IGNOREDESTALPHA,
    TAG_END]:tagitem)
    IF result <> COMPERR_SUCCESS THEN Throw("BUG", 'pAmigaGraphics; bitMapScale(); CompositeTagList() failed')
ENDPROC
The reason I can tell it is offset, is that I am scaling the bitmap using this (CompositeTagList) but the mask using the real BitMapScale (because CompositeTagList doesn't like scaling masks), and sometimes the masked area shows on one edge.
I am scaling by exactly *2, so differences in the scaling algorithm should not be an issue.
And even forcing the software implementation of CompositeTagList makes no difference! (Although as I am currently scaling non-displayable bitmaps, it would probably be using software anyway.)
Do you have any suggestions?
As an aside, I need to add a fall-back for when CompositeTagList() fails (say due to incompatible bitmap formats, e.g. when scaling masks).