Some Considerations for Display and Conversion of Apple II Double Hi-Res Graphics

 

Forward

 

 

The screen captures above, (and most of the screen captures used throughout this article), are from the AppleWin Apple IIe emulator, running in color Double Hi-Res Graphics (DHGR) mode. The AppleWin display emulates Composite Artifacting which provides subpixel rendering similar to a real Apple IIe NTSC display. The nominal resolution of DHGR is 140 x 192, which is very coarse and does not have square pixels like today’s typical display modes. For comparison purposes, the images from the screen captures above are shown below using today’s square pixel RGB display without the advantage of composite artifacting.

 

 

However, it is not composite artifacting alone that makes possible the high quality display of images converted from today’s continuous tone images in the Apple IIe’s DHGR mode, (which supports only 15 colors from a fixed palette). The high precision error diffusion dithering (E-dithering) that you see here, and throughout this article is my own, developed initially for the DHGR NTSC display of the Apple IIe. Combined with the accurate NTSC conversion palette developed by Sheldon Simms, conversions like these go far beyond what has been commonly seen in the not so distant past on the DHGR display. Keep in mind however, that DHGR emulators like the Apple IIgs fall far short of producing accurate results of a similar quality even compared to images rendered using today’s square pixel RGB display without the advantage of composite artifacting. Note that I have referred to the Apple IIgs display as a DHGR emulator, because that is merely what it is, compared to the original DHGR NTSC display of the Apple IIe.

 

Table of Contents

 

Some Considerations for Display and Conversion of Apple II Double Hi-Res Graphics. 1

Forward. 1

Table of Contents. 2

Introduction – Fun Facts. 2

Series of Articles and Background Notes – DHGR Plus. 6

Selecting the Conversion Palette for the Target DHGR Display. 7

A Severe Compromise in 16 Colors or Less. 7

Color Space and Color Matching for DHGR.. 8

A2B Source Code Listing – Setting Luma Coefficients. 8

A2B Source Code Listing – Closest Color. 9

Original Source and Win32 Download. 10

 

Introduction – Fun Facts

 

This is an article is about some of the technical considerations surrounding converting modern graphics images to Apple II Double Hi-Res Graphics (DHGR) 140 x 192 screen images using my A2B converter in conjunction with ImageMagick and other modern graphics utilities. For the most part, the results speak for themselves. It seems pretty obvious to me that the NTSC DHGR display on the Apple IIe provides a mighty fine platform for properly converted graphics like those produced by my utilities.

 

 

 

Series of Articles and Background Notes – DHGR Plus

 

The A2B Converter comes with the B2D Converter (Bmp2DHR). A2B was originally released in November 2012 as A2FCBmp (an MS-DOS companion utility for my earlier MS-DOS DHGR converter called BmpA2FC written in 2009).  Today, between both utilities, graphic images for almost every Apple II video mode can be produced. The evolution of both A2B and B2D has been continuous and ongoing, experimental and cumulative. More good news is that all the DHGR conversion features that originally appeared in each utility are still there!

 

During the time that A2B started as a command line utility included in Bmp2DHR, it was first used as a one-way converter, for converting native Apple II Double Hi-Res (DHGR) files to Windows BMP files (not as a bi-directional converter like today). A2B’s DHGR monochrome BMP output is incorporated from the MS-DOS DMONO utility also released in 2012.

 

The documentation for both A2B and B2D lags far behind their capabilities. As I added more functionality, I put my efforts into developing these utilities and not writing about them consistently, which really did little harm since the Apple II Enthusiasts that are around today are generally not interested much in displaying today’s better graphics on yesterday’s computers. In some if not most cases, it is much worse than that.

But for the few who are interested, below are some of my articles on DHGR graphics and conversion…

 

Bmp2DHR – A Utility for Converting Modern Graphics to Apple II Graphics

Disclaimer – Setting Realistic Expectations for Apple II Colors in Images Converted using Bmp2DHR

Displaying BSAVE Double Hi-Res Graphics (DHGR) Image Files in AppleSoft BASIC

Creating Double Hi-Res Graphics (DHGR) Image Fragments (“Sprites”) in Bmp2DHR – For the Apple II C Programmer

The “Mixed-Up Toy” and other “Incredible Toys” – An Apple II DHGR Programming Adventure for the C Language Programmer

Displaying Apple II Double Hi-Res Bitmapped Graphics in a cc65 C Program

Displaying Apple II Double Hi-Res Pixel Graphics in a cc65 C Program

Bmp2DHR , Apple II Graphics and Googling for Heroes

Captioning with the Tom Thumb Font in Bmp2DHR

Using an Overlay File in Bmp2DHR

Introduction to Pseudo-Palettes in Bmp2DHR  

Monochrome Dithering in Bmp2HGR – An Overview

Rolling Your Own Dithers in Bmp2DHR

Cross-Hatched Rendering for the Apple II in Bmp2DHR - The Art of Orderly Rendering and Disorderly Dithering

Bmp2DHR and VBMP

Bmp2DHR – The MS-DOS Version

Everyone’s Quick Start Guide for Converting Modern Graphics Images to Apple IIgs Super Hi-Res (SHR) Images using the A2FCBmp (A2B) Converter

Older Stuff - Apple II Bitmapped Graphics Converters

 

Some of the articles above focus on my development using the cc65 C cross-compiler. The general directory for those articles is: http://www.appleoldies.ca/cc65/docs/

 

These articles also have corresponding projects in cc65 including working versions and demos of the finished project, and also include those targeted for other Apple II graphics modes. The general directory for these projects is: http://www.appleoldies.ca/cc65/programs/

 

Selecting the Conversion Palette for the Target DHGR Display

 

The Apple II was not initially sold with a display, and instead Apple recommended that users plug into their NTSC television sets. When DHGR was introduced, Apple still did not offer a color display of its own. NTSC color television sets and 3rd party color composite monitors provided DHGR with the capability of sub-pixel rendering caused by composite artifacting, which was not possible with Apple’s introduction of their RGB displays for the Apple //e and Apple IIgs that followed. Even with an NTSC television or a composite display, the Apple IIgs took DHGR yet another step backward, by introducing an emulation of DHGR composite colors that were not the same as the original, and were instead based on the RGB display of the Apple IIgs. It is for these and related reasons that a “stock” Apple IIe with a composite display using an NTSC color televison or a composite color monitor provides the best platform for displaying converted DHGR output. Read-on!

 

A Severe Compromise in 16 Colors or Less

 

Converting from a modern continuous tone image to DHGR’s fixed palette requires a severe compromise; not only must the modern image typically be scaled down in size, to a mere 140 x 192 resolution, but 16.7 million potential 24-bit colors must be reduced to only 15-colors for composite DHGR, or 16-colors for RGB DHGR. I noted above that there are different colors for DHGR on an Apple IIgs than are on an Apple //e. So you can appreciate that mapping the reduced colors to a palette intended for an Apple //e with an NTSC television set will result in entirely different colors if displayed on an Apple IIgs with an RGB monitor, and vice-versa.      

 

The A2B Converter comes with the same built-in DHGR conversion palettes that the B2D converter uses. In my article titled Introduction to Pseudo-Palettes in Bmp2DHR, I cover the use of some of these palettes in detail. There is no getting around the fact that unlike NTSC DHGR colors, RGB DHGR colors do not balance well enough for good conversion.

 

Apple //e Composite Display

 

 

 

Apple IIgs RGB Display

 

The DHGR patterns above from Beagle Graphics that show all DHGR colors are exactly the same native-mode DHGR image displayed on the two major Apple II color DHGR displays. These are screen captures from emulators but close enough to show the difference in the “original” composite DHGR colors offered by the Apple //e and the emulated RGB DHGR colors offered by the Apple IIgs. Keep in mind that the Apple IIgs DHGR colors were just another emulator palette. As shown below, separate converted images produced using NTSC and RGB DHGR conversion palettes respectively can be used for the NTSC and RGB displays.

 

A2B and B2D NTSC Conversion Palette 5 – Used by Sheldon Simm’s tohgr for DHGR colors

This palette is derived from Sheldon Simm’s work with AppleWin NTSC’s DHGR colors

 

 

A2B and B2D RGB Conversion Palette 12 – Used by Kegs32 and Super Convert for DHGR colors

A2B and B2D NTSC Conversion Palette 5

 

 

 

A2B and B2D RGB Conversion Palette 12

A2B and B2D NTSC Conversion Palette 5

 

 

 

A2B and B2D RGB Conversion Palette 12

 

Color Space and Color Matching for DHGR

 

The A2B (and B2D) converter like many modern graphics utilities uses a Euclidian Distance Algorithm to match colors in a 24-bit image with the nearest palette color. Due to DHGR’s restriction of only 15 or 16 colors and the fact that there can be 26,880 unique colors in a scaled 24-bit input image before conversion, the A2B converter must agree mathematically with the nearest color measurements used by the “Original” input image and not use some “home-made” mapping technique to assign colors to a palette color.

 

A2B Source Code Listing – Setting Luma Coefficients

 

void setluma()

{

 

    FILE *fp;

    char buf[128];

    double dred, dgreen, dblue;

    int status = -1;

 

    /* optional text file with 3-lines,

       each with a luma coefficient for red,green and blue respectively */

    /* over-rides hard-coded luma values

       this is for someone who really knows what they are doing */

    fp = fopen("luma.txt","r");

    if (NULL != fp) {

       for (;;) {

            /* read custom luma values */

            if (NULL == fgets(buf, 128, fp)) break;

            nocr(buf);

            dred = atof(buf);

            if (NULL == fgets(buf, 128, fp)) break;

            nocr(buf);

            dgreen = atof(buf);

            if (NULL == fgets(buf, 128, fp)) break;

            nocr(buf);

            dblue = atof(buf);

            status = -2;

            /* generous range check */

            if (dred > 0.999 || dred < 0.001) break;

            if (dgreen > 0.999 || dgreen < 0.001) break;

            if (dblue > 0.999 || dblue < 0.001) break;

            /* set custom luma values */

            dlumaRED = dred; lumaRED = (int)(dred * 1000);

            dlumaGREEN = dgreen; lumaGREEN = (int)(dgreen * 1000);

            dlumaBLUE = dblue; lumaBLUE = (int)(dblue * 1000);

            status = SUCCESS;

            break;

        }

        fclose(fp);

        if (status == -1) puts("luma.txt: read error!");

        else if (status == -2) puts("luma.txt: invalid coefficient!");

        else puts("luma.txt: external coefficients in effect!");

    }

 

    if (status == SUCCESS) return;

 

    switch(lumaREQ)

    {

        /* HDMI II - Rec. 2020 specifies that if a luma (Y') signal is made that it

        uses the R’G’B’ coefficients

        0.2627 for red, 0.6780 for green, and 0.0593 for blue */

        case 2020:

                  lumaRED = 263;     lumaGREEN = 678;    lumaBLUE = 59;

                  dlumaRED = 0.2627;  dlumaGREEN = 0.6780; dlumaBLUE = 0.0593;

                  break;

 

        case 240: /* SMPTE 240M transitional coefficients */

                  /* http://www.chromapure.com/colorscience-decoding.asp */

                  lumaRED = 212;     lumaGREEN = 701;    lumaBLUE = 87;

                  dlumaRED = 0.2124;  dlumaGREEN = 0.7011; dlumaBLUE = 0.0866;

                  break;

 

        case 911: /* Sheldon Simms - tohgr - probably not useful */

                  lumaRED = 77;    lumaGREEN = 151;    lumaBLUE = 28;

                  dlumaRED = 0.077;dlumaGREEN = 0.151; dlumaBLUE = 0.028;

                  break;

 

        case 411: /* The GIMP color managed */

                  /* https://mail.gnome.org/archives/gimp-user-list/2013-November/msg00173.html */

                  /* sRGB color managed */

                  /* http://ninedegreesbelow.com/photography/srgb-luminance.html */

                  lumaRED = 223;     lumaGREEN = 717;      lumaBLUE = 61;

                  dlumaRED = 0.2225; dlumaGREEN = 0.7169;  dlumaBLUE = 0.0606;

                  break;

 

        case 709: /* CCIR 709 - modern */

                  /* ImageMagick non-color managed */

                  /* also The GIMP 2.8 - http://fossies.org/dox/gimp-2.8.14/gimprgb_8h_source.html */

                  /* also PhotoShop

                     http://www.beneaththewaves.net/Photography/Secrets_of_Photoshops_Colour_Blend_Mode_Revealed_Sort_Of.html

                  */

                  lumaRED = 213;      lumaGREEN = 715;       lumaBLUE = 72;

                  dlumaRED = 0.212656;dlumaGREEN = 0.715158; dlumaBLUE = 0.072186;

                  break;

 

        case 601: /* CCIR 601 - most digital standard definition formats */

                  /* for monitors having phosphors that were contemporary

                     at the introduction of NTSC television in 1953.

                  /* these coefficients do not accurately compute luminance for contemporary monitors */

 

        default:  lumaRED = 299;     lumaGREEN = 587;      lumaBLUE = 114;

                  dlumaRED = 0.298839;  dlumaGREEN = 0.586811;   dlumaBLUE = 0.114350;

                  break;

 

 

    }

}

 

A2B’s conversion palettes must also agree mathematically with the color science used by the “Original” input image and with all transformations of that input image, including cropping and padding, and scaling and saving. In all of this, the standardization of Color Space is important.

 

Like many if not most modern graphics editors, the A2B converter understands and implements standard color spaces, using standard Luma coeffients and color gamuts to match colors to target displays.

 

For example if we were targeting an  NTSC television for DHGR output using a properly phased signal from an Apple IIe, we would use a hard-coded 15-color 24-bit conversion palette based on Sheldon Simm’s work with the AppleWin NTSC emulator and the tohgr converter. We could use Rec. 601 Luma coefficients to re-map the modern color gamut even though the “Original” input image likely uses sRGB color space. Because there is some debate (in my mind and in the wild) whether Rec. 709 Luma coefficients are a better bet for mapping from a modern image, for the purposes of the conversions in this article I have stayed with Rec. 709.

 

But if we were targeting an Apple IIgs RGB display with a crt monitor for DHGR output, we would use a hard-coded 16-color 24-bit conversion palette based on Super Convert and also used by the Kegs32 emulator. We would use Rec. 709 Luma coefficients to map the modern color gamut “as-is”. But our results still wouldn’t be as good as on an Apple IIe with a television as a monitor, because the Apple IIgs RGB display’s DHGR colors are not phased perfectly like the Apple IIe’s NTSC DHGR colors, and the RGB display does not provide NTSC artifacting which creates the advantage of subpixel rendering. As far as plugging a television into the the Apple IIgs composite output; it still uses the RGB display’s DHGR colors so even though artifacting occurs it has lost the advantage of the properly phased colors of the Apple IIe composite output.

 

A2B Source Code Listing – Closest Color

 

/* use CCIR 601 luminosity to get closest color in current palette */

/* based on palette that has been selected for conversion */

uchar GetClosestColor(uchar r, uchar g, uchar b)

{

    uchar drawcolor;

    double dr, dg, db, diffR, diffG, diffB, luma, lumadiff, distance, prevdistance;

    int i,j=brooksline;

 

    globaldistance = 0.0;

 

    /* look for exact match */

    for (i=0;i<16;i++) {

        if (brooksline == 999) {

            if (r == rgbArray[i][0] && g == rgbArray[i][1] && b == rgbArray[i][2]) return (uchar)i;

        }

        else {

            if (r == rgbArrays[j][i][0] && g == rgbArrays[j][i][1] && b == rgbArrays[j][i][2]) return (uchar)i;

        }

    }

 

    /* if no exact match use nearest color */

    dr = (double)r;

    dg = (double)g;

    db = (double)b;

    luma = (dr*lumaRED + dg*lumaGREEN + db*lumaBLUE) / (255.0*1000);

    lumadiff = rgbLuma[0]-luma;

 

    /* Compare the difference of RGB values, weigh by CCIR 601 luminosity */

    /* set palette index to color with shortest distance */

 

    /* get color distance to first palette color */

    diffR = (rgbDouble[0][0]-dr)/255.0;

    diffG = (rgbDouble[0][1]-dg)/255.0;

    diffB = (rgbDouble[0][2]-db)/255.0;

 

    prevdistance = (diffR*diffR*dlumaRED + diffG*diffG*dlumaGREEN + diffB*diffB*dlumaGREEN)*0.75

         + lumadiff*lumadiff;

    /* set palette index to first color */

    drawcolor = 0;

 

    /* get color distance to rest of palette colors */

    for (i=1;i<16;i++) {

 

        /* get color distance of this index */

        lumadiff = rgbLuma[i]-luma;

        diffR = (rgbDouble[i][0]-dr)/255.0;

        diffG = (rgbDouble[i][1]-dg)/255.0;

        diffB = (rgbDouble[i][2]-db)/255.0;

        distance = (diffR*diffR*dlumaRED + diffG*diffG*dlumaGREEN + diffB*diffB*dlumaBLUE)*0.75

            + lumadiff*lumadiff;

 

        /* if distance is smaller use this index */

        if (distance < prevdistance) {

           prevdistance = distance;

           drawcolor = (uchar)i;

        }

 

    }

    globaldistance = prevdistance;

    return drawcolor;

}

 

This is admittedly not as straight-forward as just running some old GIF converter and hoping for the best.

 

Original Source and Win32 Download

 

http://www.appleoldies.ca/cc65/programs/dhgr/bmp2dhr.zip

 

You have a royalty-free right to use, modify, reproduce and distribute the above zip file including source code in any way you find useful, provided that you agree that Bill Buckels has no warranty obligations or liability resulting from said distribution in any way whatsoever.

 

Bill Buckels

bbuckels@mts.net

January 10, 2017