apple2gs_shr_converter/src_a2b/a2fcbmp.c

8600 lines
293 KiB
C
Executable File
Raw Permalink Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/* ------------------------------------------------------------------------ */
/* A2FCBMP.C (C) Copyright Bill Buckels 2012-2015 */
/* All Rights Reserved. */
/* */
/* Licence Agreement */
/* ----------------- */
/* */
/* You have a royalty-free right to use, modify, reproduce and */
/* distribute this 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. */
/* If you don't agree, remove this source code from your computer now. */
/* */
/* Written by : Bill Buckels */
/* Email: bbuckels@mts.net */
/* */
/* Purpose : This utility will allow you to convert from */
/* Apple II Double Hi-Res 140 x 192 x 16 color images to: */
/* */
/* 280 x 192 x 24 Bit Windows .BMP Files - Default */
/* 140 x 192 x 24 Bit Windows .BMP Files - Option "140" */
/* */
/* Variable sized color BMP output from DHR Image Fragments in both */
/* nominal sizes listed above is also supported. */
/* */
/* Option "P" (p0-p16) Color Mapping is in one of 16 optional palettes.*/
/* The palette numbers are the same as Bmp2DHR: */
/* */
/* 0 - Kegs32 (RGB) */
/* 1 - CiderPress (RGB) */
/* 2 - Old AppleWin (NTSC ?) */
/* 3 - New AppleWin (NTSC ?) */
/* 4 - Wikipedia (NTSC) */
/* 5 - tohgr (NTSC) */
/* palette 6 is a user palette file */
/* palettes 7-11 are IBM-PC legacy palettes */
/* palette 12 is Super Convert RGB palette */
/* palette 13 is Jace NTSC palette */
/* palette 14 is Cybernesto's VBMP NTSC palette */
/* palette 15 is merged RGB-NTSC colors (p5+p12)/2 */
/* palette 16 is tohgr's old NTSC colors */
/* */
/* This utility will also allow you to convert from */
/* Apple II Double Hi-Res 560 x 192 monochrome images to: */
/* */
/* 560 x 384 monochrome Windows .BMP Files - Option "384" */
/* 560 x 192 monochrome Windows .BMP Files - Option "192" */
/* */
/* This utility also converts from an AppleWin "Mono" */
/* screen capture 256 color BMP to any of the Above. */
/* */
/* During conversion of the AppleWin 256 color BMP it also */
/* generates Apple II Double Hi-Res images and renames the */
/* AppleWin BMP. */
/* */
/* Revision : 3.0 Added AppleWin Support and odds and ends. */
/* 4.0 Added Different Palettes */
/* Added Long FileNames for 32 bit compilation */
/* Added optional Ciderpress tags for Long Filenames */
/* Added support for XPACK DHR image fragments */
/* Added support for Sheldon Simms DHGR naming for A2FC */
/* 5.0 Expanded Features and output beyond DHGR */
/* 6.0 May 2015 */
/* 7.0 July 2015 */
/* 8.0 November 2015 */
/* ------------------------------------------------------------------------ */
/* Originally Written in Large Model 16 bit Microsoft C (MSC) Version 8.00c */
/* Cleaned-up c++ code comments for old Turbo C 2.0 */
/* 16-bit MS-DOS version now compiles under both */
/* MSC and Turbo C */
/* ------------------------------------------------------------------------ */
/* Added Conditional Compilation for MinGW and gcc */
/* Added Conditional Compilation etc. for 32 bit support */
/* 32-bit version now compiles under Visual Studio Win32 */
/* and MinGW Win32 and gcc with support for long names. */
/* Should now run everywhere (Windows, Linux, OSX) */
/* ------------------------------------------------------------------------ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <math.h>
#define LOBLACK 0
#define LORED 1
#define LODKBLUE 2
#define LOPURPLE 3
#define LODKGREEN 4
#define LOGRAY 5
#define LOMEDBLUE 6
#define LOLTBLUE 7
#define LOBROWN 8
#define LOORANGE 9
#define LOGREY 10
#define LOPINK 11
#define LOLTGREEN 12
#define LOYELLOW 13
#define LOAQUA 14
#define LOWHITE 15
/* dither types */
#define FLOYDSTEINBERG 1
#define JARVIS 2
#define STUCKI 3
#define ATKINSON 4
#define BURKES 5
#define SIERRA 6
#define SIERRATWO 7
#define SIERRALITE 8
#define BUCKELS 9
#define ATKINSON2 10
/* ------------------------------------------------------------------------ */
/* Declarations, Vars. etc. */
/* ------------------------------------------------------------------------ */
/* options flags */
int longnames = 1, bmp = 0, bm2 = 0, bmp3 = 0, a2fc = 0, auxbin = 0, tohgr = 0, dhr = 0, frag = 0,
mono = 0, doublepixel = 1, applesoft = 0, palnumber = 5, doublegrey = 0, vbmp = 0,
dither = 0, dithertype = 9, randomdither = 0, errorsum = 0, outline = 0, lores = 0, doublelores = 0, tags=0, dosheader=0;
int shr = 0, shrgrey = 0, usegscolors = 0, usegspalette = 0, hsl = 1, shrpalette = 15, brooks = 0, shrmode = 0, shrpalettes = 1,
shr256 = 0, useimagetone = 0, usepalettedistance = 0, quietmode = 1, m2s = 0, shrinput = 0, mix256 = 0,
imnumpalettes = 0, fourbit = 0, fourplay = 0, fourpal = 0;
double desaturate[16];
char fullname[256], shortname[256], outname[256], mainfile[256],auxfile[256],a2fcfile[256];
char *palname[] = {
"Kegs32 RGB",
"CiderPress RGB",
"Old AppleWin NTSC",
"New AppleWin NTSC",
"Wikipedia NTSC",
"tohgr NTSC DHGR",
"Imported",
"Legacy Canvas",
"Legacy Win16",
"Legacy Win32",
"Legacy VGA BIOS",
"Legacy VGA PCX",
"Super Convert RGB",
"Jace NTSC",
"Cybernesto-Munafo NTSC",
"Pseudo Palette",
"tohgr NTSC HGR"};
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned long ulong;
typedef short sshort;
/* put this here for now */
/* shr colors start */
uchar ColorsUsed[16][16][16];
int shrcolorcount = 0;
/* for checking duplicate 12-bit colors in 24-bit conversion palettes */
/* expand as necessary */
int shrdupedebug = 0, shrdupes = 0, shrdupecount = 0;
void shrcolorsused(uchar r, uchar g, uchar b)
{
r = r >> 4;
g = g >> 4;
b = b >> 4;
if (ColorsUsed[r][g][b] == 0) {
ColorsUsed[r][g][b] = 1;
shrcolorcount++;
}
else if (shrdupedebug != 0 && r !=0 && g != 0 && b != 0) {
/* do not count black as dupes */
if (ColorsUsed[r][g][b] == 1) {
ColorsUsed[r][g][b] = 2;
shrdupes = 1;
}
shrdupecount++;
}
}
void clearcolorsused()
{
shrcolorcount = shrdupecount = shrdupes = 0;
memset(&ColorsUsed[0][0][0],0,4096);
}
/* shr colors end */
/* Bitmap Header structures */
#ifdef MINGW
typedef struct __attribute__((__packed__)) tagRGBQUAD
#else
typedef struct tagRGBQUAD
#endif
{
unsigned char rgbBlue;
unsigned char rgbGreen;
unsigned char rgbRed;
unsigned char rgbReserved;
} RGBQUAD;
/* Bitmap Header structures */
#ifdef MINGW
typedef struct __attribute__((__packed__)) tagBITMAPINFOHEADER
#else
typedef struct tagBITMAPINFOHEADER
#endif
{
ulong biSize;
ulong biWidth;
ulong biHeight;
ushort biPlanes;
ushort biBitCount;
ulong biCompression;
ulong biSizeImage;
ulong biXPelsPerMeter;
ulong biYPelsPerMeter;
ulong biClrUsed;
ulong biClrImportant;
} BITMAPINFOHEADER;
/* Not officially documented - BITMAPV2INFOHEADER */
#ifdef MINGW
typedef struct __attribute__((__packed__)) tagBITMAPINFOHEADERV2
#else
typedef struct tagBITMAPINFOHEADERV2
#endif
{
ulong biSize;
ulong biWidth;
ulong biHeight;
ushort biPlanes;
ushort biBitCount;
ulong biCompression;
ulong biSizeImage;
ulong biXPelsPerMeter;
ulong biYPelsPerMeter;
ulong biClrUsed;
ulong biClrImportant;
ulong biRedMask;
ulong biGreenMask;
ulong biBlueMask;
} BITMAPINFOHEADERV2;
/* Not officially documented - BITMAPV3INFOHEADER */
#ifdef MINGW
typedef struct __attribute__((__packed__)) tagBITMAPINFOHEADERV3
#else
typedef struct tagBITMAPINFOHEADERV3
#endif
{
ulong biSize;
ulong biWidth;
ulong biHeight;
ushort biPlanes;
ushort biBitCount;
ulong biCompression;
ulong biSizeImage;
ulong biXPelsPerMeter;
ulong biYPelsPerMeter;
ulong biClrUsed;
ulong biClrImportant;
ulong biRedMask;
ulong biGreenMask;
ulong biBlueMask;
ulong biAlphaMask;
} BITMAPINFOHEADERV3;
#ifdef MINGW
typedef struct __attribute__((__packed__)) tagBITMAPINFOHEADERV4
#else
typedef struct tagBITMAPINFOHEADERV4
#endif
{
ulong biSize;
ulong biWidth;
ulong biHeight;
ushort biPlanes;
ushort biBitCount;
ulong biCompression;
ulong biSizeImage;
ulong biXPelsPerMeter;
ulong biYPelsPerMeter;
ulong biClrUsed;
ulong biClrImportant;
ulong biRedMask;
ulong biGreenMask;
ulong biBlueMask;
ulong biAlphaMask;
ulong biCSType;
uchar biEndpoints[36]; /* CIEXYZTRIPLE */
ulong biGammaRed;
ulong biGammaGreen;
ulong biGammaBlue;
} BITMAPINFOHEADERV4;
#ifdef MINGW
typedef struct __attribute__((__packed__)) tagBITMAPINFOHEADERV5
#else
typedef struct tagBITMAPINFOHEADERV5
#endif
{
ulong biSize;
ulong biWidth;
ulong biHeight;
ushort biPlanes;
ushort biBitCount;
ulong biCompression;
ulong biSizeImage;
ulong biXPelsPerMeter;
ulong biYPelsPerMeter;
ulong biClrUsed;
ulong biClrImportant;
ulong biRedMask;
ulong biGreenMask;
ulong biBlueMask;
ulong biAlphaMask;
ulong biCSType;
uchar biEndpoints[36]; /* CIEXYZTRIPLE */
ulong biGammaRed;
ulong biGammaGreen;
ulong biGammaBlue;
ulong biIntent;
ulong biProfileData;
ulong biProfileSize;
ulong biReserved;
} BITMAPINFOHEADERV5;
#ifdef MINGW
typedef struct __attribute__((__packed__)) tagBITMAPFILEHEADER
#else
typedef struct tagBITMAPFILEHEADER
#endif
{
uchar bfType[2];
ulong bfSize;
ushort bfReserved1;
ushort bfReserved2;
ulong bfOffBits;
} BITMAPFILEHEADER;
#ifdef MINGW
typedef struct __attribute__((__packed__)) tagBMPHEADER
#else
typedef struct tagBMPHEADER
#endif
{
BITMAPFILEHEADER bfi;
BITMAPINFOHEADER bmi;
} BMPHEADER;
/* picfile trailer structure */
#ifdef MINGW
typedef struct __attribute__((__packed__)) tagPICFILE
#else
typedef struct tagPICFILE
#endif
{
uchar scb[200];
uchar padding[56];
uchar pal[200][32]; /* note the PIC file has 16 palette entries */
} PICFILE;
/* constant for the biCompression field */
#define BI_RGB 0L
/* static structures for processing bmp input files */
BITMAPFILEHEADER BitMapFileHeader;
RGBQUAD sbmp[256]; /* super vga - applewin */
sshort palettesused = 0, palettecolorsused[16];
BITMAPINFOHEADER bmi;
/* support for BMP version 4 but not sure about other versions */
BITMAPINFOHEADERV5 bmiV5;
/* DHR Image Fragments - Sprites */
BMPHEADER mybmp;
ushort bmpwidth = 0, bmpheight = 0, fragwidth = 140, fragheight = 192, fragx = 0, fragy = 0;
/* SHR PIC file */
PICFILE mypic;
#define ASCIIZ 0
#define CRETURN 13
#define LFEED 10
uchar *szTextTitle =
"A2FCBmp(C) Version 8.0 Copyright Bill Buckels 2012-2015\n"
"All Rights Reserved.";
#define SUCCESS 0
#define VALID SUCCESS
#define FAILURE -1
#define INVALID FAILURE
#define NUM_RGB_COLORS 3
#define NUM_VGA_COLORS 16
/* 280 x 192 - the default output format */
uchar BMP_header[] ={
0x42, 0x4D, 0x36, 0x76, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0xC0, 0x00,
0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x76, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/* 140 x 192 - verbatim output format */
uchar BMP140_header[] ={
0x42, 0x4D, 0x36, 0x3B, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0xC0, 0x00,
0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3B, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/* monochrome output routines - ported from dmono */
/* headers for monochrome BMP files */
/* 560 x 384 - the default output format */
uchar mono384[62] ={
0x42, 0x4D, 0x3E, 0x6C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x30, 0x02, 0x00, 0x00, 0x80, 0x01,
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00};
/* 560 x 192 - verbatim output format */
uchar mono192[62] ={
0x42, 0x4D, 0x3E, 0x36, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x30, 0x02, 0x00, 0x00, 0xC0, 0x00,
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00};
uchar msk[]={0x80,0x40,0x20,0x10,0x8,0x4,0x2,0x1};
uchar bmpscanline[1680], bmpscanline2[1680];
uchar buf560[560];
/* built-in palette options */
/* based on DHGR, DLGR, LGR colors */
/* LGR color order */
uchar kegs32colors[16][3] = {
0,0,0, /* black */
221,0,51, /* red */
0,0,153, /* dk blue */
221,0,221, /* purple */
0,119,0, /* dk green */
85,85,85, /* gray */
34,34,255, /* med blue */
102,170,255, /* lt blue */
136,85,34, /* brown */
255,102,0, /* orange */
170,170,170, /* grey */
255,153,136, /* pink */
0,221,0, /* lt green */
255,255,0, /* yellow */
0,255,153, /* aqua */
255,255,255};/* white */
uchar ciderpresscolors[16][3] = {
0,0,0, /* black */
221,0,51, /* red */
0,0,153, /* dk blue */
221,34,221, /* purple */
0,119,34, /* dk green */
85,85,85, /* gray */
34,34,255, /* med blue */
102,170,255, /* lt blue */
136,85,0, /* brown */
255,102,0, /* orange */
170,170,170, /* grey */
255,153,136, /* pink */
17,221,0, /* lt green */
255,255,0, /* yellow */
68,255,153, /* aqua */
255,255,255};/* white */
uchar awinoldcolors[16][3] = {
0,0,0, /* black */
208,0,48, /* red */
0,0,128, /* dk blue */
255,0,255, /* purple */
0,128,0, /* dk green */
128,128,128, /* gray */
0,0,255, /* med blue */
96,160,255, /* lt blue */
128,80,0, /* brown */
255,128,0, /* orange */
192,192,192, /* grey */
255,144,128, /* pink */
0,255,0, /* lt green */
255,255,0, /* yellow */
64,255,144, /* aqua */
255,255,255};/* white */
uchar awinnewcolors[16][3] = {
0,0,0, /* black */
157,9,102, /* red */
42,42,229, /* dk blue */
199,52,255, /* purple */
0,118,26, /* dk green */
128,128,128, /* gray */
13,161,255, /* med blue */
170,170,255, /* lt blue */
85,85,0, /* brown */
242,94,0, /* orange */
192,192,192, /* grey */
255,137,229, /* pink */
56,203,0, /* lt green */
213,213,26, /* yellow */
98,246,153, /* aqua */
255,255,255};/* white */
/* http://en.wikipedia.org/wiki/List_of_8-bit_computer_hardware_palettes */
uchar wikipedia[16][3] = {
0,0,0, /* black */
114,38,64, /* red */
64,51,127, /* dk blue */
228,52,254, /* purple */
14,89,64, /* dk green */
128,128,128, /* gray */
27,154,254, /* med blue */
191,179,255, /* lt blue */
64,76,0, /* brown */
228,101,1, /* orange */
128,128,128, /* grey */
241,166,191, /* pink */
27,203,1, /* lt green */
191,204,128, /* yellow */
141,217,191, /* aqua */
255,255,255};/* white */
/* http://wsxyz.net/tohgr.html */
/* Sheldon Simm's palette from todhr */
/*
Sheldon is clipping the black and white ranges.
The usual reason for doing this is for dirty images (caused by poor digitizing or
sampling or re-sampling color depth loss due to scaling). By using a clipping threshold
at either end of the rgb range, blacks that are not quite black don't match to some other
dark color and whites that are not quite white don't match to some other light color.
I too put this in place as a clipping option when I wrote Bmp2SHR about a year ago in my
Brooks output routines but it worked a little differently. I didn't build it into a
palette for one thing.
Sheldon's weighting favours clipping blue gun values at both ends of the range.
Red is clipped more than green in the high range, and green is clipped more than
red in the low range.
static Pixel pal[] = {
{ 1, 4, 8}, // 0 black
{ 32, 54, 212}, // 1 dk blue
{ 51, 111, 0}, // 2 dk green
{ 7, 168, 225}, // 3 med blue
{ 99, 77, 0}, // 4 brown
{ 126, 126, 126}, // 5 gray
{ 67, 200, 0}, // 6 lt green
{ 93, 248, 133}, // 7 aqua
{ 148, 12, 125}, // 8 red
{ 188, 55, 255}, // 9 purple
{ 126, 126, 126}, // A grey
{ 158, 172, 255}, // B lt blue
{ 249, 86, 29}, // C orange
{ 255, 129, 236}, // D pink
{ 221, 206, 23}, // E yellow
{ 248, 250, 244} // F white
Also note that I use the array name grpal. This was used as a palette in
one of Sheldon's previous versions. Since I have propagated this array name
to my code and my code is working fine with it, I have no plans to change it
to maintain currency with Sheldon's code.
*/
uchar grpal[16][3] = {
0,0,0, /* black */
148,12,125, /* red - hgr 0*/
32,54,212, /* dk blue - hgr 0 */
188,55,255, /* purple - default HGR overlay color */
51,111,0, /* dk green - hgr 0 */
126,126,126, /* gray - hgr 0 */
7,168,225, /* med blue */
158,172,255, /* lt blue - hgr 0 - alternate HGR overlay color*/
99,77,0, /* brown - hgr 0 */
249,86,29, /* orange */
126,126,126, /* grey - hgr 0 */
255,129,236, /* pink - hgr 0 */
67,200,0, /* lt green */
221,206,23, /* yellow - hgr 0 */
93,248,133, /* aqua - hgr 0 */
255,255,255};/* white */
/* Sheldon still uses the RGB values from his old palette for HGR conversion */
uchar hgrpal[16][3] = {
0x00,0x00,0x00, /* black */
0xad,0x18,0x28, /* red */
0x55,0x1b,0xe1, /* dk blue */
0xe8,0x2c,0xf8, /* purple 232,44,248 - default hgr overlay color */
0x01,0x73,0x63, /* dk green */
0x7e,0x82,0x7f, /* gray */
0x34,0x85,0xfc, /* med blue - 52,133,252 - alternate HGR overlay color */
0xd1,0x95,0xff, /* lt blue */
0x33,0x6f,0x00, /* brown */
0xd0,0x81,0x01, /* orange */
0x7f,0x7e,0x77, /* grey */
0xfe,0x93,0xa3, /* pink */
0x1d,0xd6,0x09, /* lt green */
0xae,0xea,0x22, /* yellow */
0x5b,0xeb,0xd9, /* aqua */
0xff,0xff,0xff};/* white */
/* imported palette file */
uchar rgbUser[16][3];
uchar SuperConvert[16][3] = {
0,0,0, /* black */
221,0,51, /* red */
0,0,153, /* dk blue */
221,0,221, /* purple */
0,119,0, /* dk green */
85,85,85, /* gray */
34,34,255, /* med blue */
102,170,255, /* lt blue */
136,85,34, /* brown */
255,102,0, /* orange */
170,170,170, /* grey */
255,153,136, /* pink */
0,221,0, /* lt green */
255,255,0, /* yellow */
0,255,153, /* aqua */
255,255,255};/* white */
uchar Jace[16][3] = {
0,0,0, /* black */
177,0,93, /* red */
32,41,255, /* dk blue */
210,41,255, /* purple */
0,127,34, /* dk green */
127,127,127, /* gray */
0,168,255, /* med blue */
160,168,255, /* lt blue */
94,86,0, /* brown */
255,86,0, /* orange */
127,127,127, /* grey */
255,127,220, /* pink */
44,213,0, /* lt green */
222,213,0, /* yellow */
77,255,161, /* aqua */
255,255,255}; /* white */
/* https://github.com/cybernesto/VBMP/wiki/Converting-a-picture-into-a-DHGR-color-image-using-the-GIMP */
/* Robert Munafo - http://mrob.com/pub/xapple2/colors.html */
uchar Cybernesto[16][3] = {
0, 0, 0, /* 0 Black */
227, 30, 96, /* 1 Magenta */
96, 78,189, /* 8 Dark Blue */
255, 68,253, /* 9 Violet */
0,163, 96, /* 4 Dark Green */
156,156,156, /* 5 Grey1 */
20,207,253, /* 12 Medium Blue */
208,195,255, /* 13 Light Blue */
96,114, 3, /* 2 Brown */
255,106, 60, /* 3 Orange */
156,156,156, /* 10 Grey2 */
255,160,208, /* 11 Pink */
20,245, 60, /* 6 Green */
208,221,141, /* 7 Yellow */
114,255,208, /* 14 Aqua */
255,255,255}; /* 15 White */
/* merged palette */
/* initial values are the average values of p5 NTSC and p12 RGB */
uchar PseudoPalette[16][3] = {
0,0,0,
184,6,88,
16,27,182,
204,27,238,
25,115,0,
105,105,105,
20,101,240,
130,171,255,
117,81,17,
252,94,14,
148,148,148,
255,141,186,
33,210,0,
238,230,11,
46,251,143,
255,255,255};
/* goes with the canvas bmp that I put out there with AppleX */
uchar rgbCanvasArray[16][3] = {
0 , 0 , 0 ,
208, 0 , 48 ,
0 , 0 , 128,
255, 0 , 255,
0 , 128, 0 ,
128, 128, 128,
0 , 0 , 255,
96 , 160, 255,
128, 80 , 0 ,
255, 128, 0 ,
192, 192, 192,
255, 144, 128,
0 , 255, 0 ,
255, 255, 0 ,
64 , 255, 144,
255, 255, 255};
/* this might work with old Win16 16 color BMP's */
uchar rgbBmpArray[16][3] = {
0 ,0 , 0 ,
191,0 , 0 ,
0 ,0 , 191,
191,0 , 191,
0 ,191, 0 ,
128,128, 128,
0 ,191, 191,
0 ,0 , 255,
191,191, 0 ,
255,0 , 0 ,
192,192, 192,
255,0 , 255,
0 ,255, 0 ,
255,255, 0 ,
0 ,255, 255,
255,255, 255};
/* this might work with new Win32 16 color BMP's */
uchar rgbXmpArray[16][3] = {
0 , 0 , 0 ,
128, 0 , 0 ,
0 , 0 , 128,
128, 0 , 128,
0 , 128, 0 ,
128, 128, 128,
0 , 128, 128,
0 , 0 , 255,
128, 128, 0 ,
255, 0 , 0 ,
192, 192, 192,
255, 0 , 255,
0 , 255, 0 ,
255, 255, 0 ,
0 , 255, 255,
255, 255, 255};
/* from the bios in some PC I had */
uchar rgbVgaArray[16][3] = {
0 , 0 , 0 ,
255, 0 , 0 ,
0 , 0 , 255,
255, 0 , 255,
0 , 255, 0 ,
85 , 85 , 85 ,
0 , 255, 255,
85 , 85 , 255,
255, 255, 0 ,
255, 85 , 85 ,
192, 192, 192,
255, 85 , 255,
85 , 255, 85 ,
255, 255, 85 ,
85 , 255, 255,
255, 255, 255};
/* some old ZSoft VGA Pcx Colors */
uchar rgbPcxArray[16][3] = {
0 , 0 , 0 ,
170, 0 , 0 ,
0 , 0 , 170,
170, 0 , 170,
0 , 170, 0 ,
85 , 85 , 85 ,
0 , 170, 170,
85 , 85 , 255,
170, 170, 0 ,
255, 85 , 85 ,
170, 170, 170,
255, 85 , 255,
85 , 255, 85 ,
255, 255, 85 ,
85 , 255, 255,
255, 255, 255};
/* our working copy of the apple II double hires colors */
/* this is in Apple II lo-res color order */
/* todhr palette */
uchar rgbArray[NUM_VGA_COLORS][NUM_RGB_COLORS]={
0,0,0, /* black */
148,12,125, /* red */
32,54,212, /* dk blue */
188,55,255, /* purple */
51,111,0, /* dk green */
126,126,126, /* gray */
7,168,225, /* med blue */
158,172,255, /* lt blue */
99,77,0, /* brown */
249,86,29, /* orange */
126,126,126, /* grey */
255,129,236, /* pink */
67,200,0, /* lt green */
221,206,23, /* yellow */
93,248,133, /* aqua */
255,255,255};/* white */
char *colornames[] = {
"black",
"red",
"dkblue",
"purple",
"dkgreen",
"gray",
"medblue",
"ltblue",
"brown",
"orange",
"grey",
"pink",
"ltgreen",
"yellow",
"aqua",
"white"};
/* for SHR output */
/* 200 brooks palettes */
uchar rgbArrays[200][16][3];
uchar rgbUsed[200][16];
double rgbDistance[200][16];
/* save palettes for palette distance resassignment */
uchar savepalettes[200][16][3];
uchar savescb[200];
/* 16 pic palettes */
uchar rgb256Arrays[200][16][3];
uchar rgb256Used[16][16];
double rgb256Distance[16][16];
/* all possible EGA ECD Values in Indexed Order */
uchar rgbEgaArray[64][3] = {
0x00, 0x00, 0x00,
0x00, 0x00, 0xaa,
0x00, 0xaa, 0x00,
0x00, 0xaa, 0xaa,
0xaa, 0x00, 0x00,
0xaa, 0x00, 0xaa,
0xaa, 0xaa, 0x00,
0xaa, 0xaa, 0xaa,
0x00, 0x00, 0x55,
0x00, 0x00, 0xff,
0x00, 0xaa, 0x55,
0x00, 0xaa, 0xff,
0xaa, 0x00, 0x55,
0xaa, 0x00, 0xff,
0xaa, 0xaa, 0x55,
0xaa, 0xaa, 0xff,
0x00, 0x55, 0x00,
0x00, 0x55, 0xaa,
0x00, 0xff, 0x00,
0x00, 0xff, 0xaa,
0xaa, 0x55, 0x00,
0xaa, 0x55, 0xaa,
0xaa, 0xff, 0x00,
0xaa, 0xff, 0xaa,
0x00, 0x55, 0x55,
0x00, 0x55, 0xff,
0x00, 0xff, 0x55,
0x00, 0xff, 0xff,
0xaa, 0x55, 0x55,
0xaa, 0x55, 0xff,
0xaa, 0xff, 0x55,
0xaa, 0xff, 0xff,
0x55, 0x00, 0x00,
0x55, 0x00, 0xaa,
0x55, 0xaa, 0x00,
0x55, 0xaa, 0xaa,
0xff, 0x00, 0x00,
0xff, 0x00, 0xaa,
0xff, 0xaa, 0x00,
0xff, 0xaa, 0xaa,
0x55, 0x00, 0x55,
0x55, 0x00, 0xff,
0x55, 0xaa, 0x55,
0x55, 0xaa, 0xff,
0xff, 0x00, 0x55,
0xff, 0x00, 0xff,
0xff, 0xaa, 0x55,
0xff, 0xaa, 0xff,
0x55, 0x55, 0x00,
0x55, 0x55, 0xaa,
0x55, 0xff, 0x00,
0x55, 0xff, 0xaa,
0xff, 0x55, 0x00,
0xff, 0x55, 0xaa,
0xff, 0xff, 0x00,
0xff, 0xff, 0xaa,
0x55, 0x55, 0x55,
0x55, 0x55, 0xff,
0x55, 0xff, 0x55,
0x55, 0xff, 0xff,
0xff, 0x55, 0x55,
0xff, 0x55, 0xff,
0xff, 0xff, 0x55,
0xff, 0xff, 0xff};
sshort rgb2ega(uchar red, uchar green, uchar blue)
{
/* Converts from 24 bit color to Ega color index
EGA with ECD 16 color registers (0-63) 1 byte each */
sshort idx = 0;
/* find gun value index for EGA table comparison using thresholds */
if (red < 43) red = 0; /* 0x00 */
else if (red < 128) red = 85; /* 0x55 */
else if (red < 224) red = 170; /* 0xaa */
else red = 255; /* 0xff */
if (green < 43) green = 0;
else if (green < 128) green = 85;
else if (green < 213) green = 170;
else green = 255;
if (blue < 43) blue = 0;
else if (blue < 128) blue = 85;
else if (blue < 213) blue = 170;
else blue = 255;
/* values are now identicalized so use comparators in arrays to
determine ega color index
visual verification can be found at:
standard - http:en.wikipedia.org/wiki/Enhanced_Graphics_Adapter
extended - http:en.wikipedia.org/wiki/Image:EGA_Table.PNG
discussion about bit patterns and visuals also there */
for (idx = 0; idx < 64; idx++) {
if (red == rgbEgaArray[idx][0] &&
green == rgbEgaArray[idx][1] &&
blue == rgbEgaArray[idx][2]) return idx;
}
/* never gets to here */
return 0;
}
sshort globalthreshold = 4, rhold = 4, ghold = 4, bhold = 4;
/* set thresholds for color reduction on 24 bit values */
uchar sethold(uchar ch, sshort hold)
{
if (hold == 0) return ch;
/* just hand-bombed some hardcoded color thresholds here
they probably work just about as well as anything */
switch(hold) {
case 0:
if (ch < 192) ch = 0;
else ch = 255;
break;
case 1:
if (ch < 64) ch = 0;
else ch = 255;
break;
case 2:
if (ch < 128) ch = 0;
else ch = 255;
break;
case 3:
/* adjust gun values using EGA-like thresholds */
/* mode640 optimized threshold option */
if (ch < 85) ch = 0; /* 0x00 */
else if (ch < 170) ch = 128;
else ch = 255; /* 0xff */
break;
case 4:
/* adjust gun values using EGA-like thresholds */
/* threshold default option */
if (ch < 43) ch = 0; /* 0x00 */
else if (ch < 128) ch = 85; /* 0x55 */
else if (ch < 224) ch = 170; /* 0xaa */
else ch = 255; /* 0xff */
break;
/* additional thresholds */
case 5:
if (ch < 25) ch = 0; /* 0x00 */
else if (ch < 76) ch = 51;
else if (ch < 127) ch = 102;
else if (ch < 178) ch = 153;
else if (ch < 229) ch = 204;
else ch = 255; /* 0xff */
break;
case 6:
/* mode320 optimized threshold option */
if (ch < 0x15) ch = 0; /* 0x00 */
else if (ch < 0x3F) ch = 0x2A;
else if (ch < 0x69) ch = 0x54;
else if (ch < 0x93) ch = 0x7E;
else if (ch < 0xbd) ch = 0xa8;
else if (ch < 0xe7) ch = 0xd6;
else ch = 255; /* 0xff */
break;
case 7:
if (ch < 18) ch = 0; /* 0x00 */
else if (ch < 54) ch = 36;
else if (ch < 90) ch = 72;
else if (ch < 126) ch = 108;
else if (ch < 162) ch = 144;
else if (ch < 198) ch = 180;
else if (ch < 234) ch = 216;
else ch = 255; /* 0xff */
break;
case 8:
if (ch < 0x10) ch = 0; /* 0x00 */
else if (ch < 0x30) ch = 0x20;
else if (ch < 0x50) ch = 0x40;
else if (ch < 0x70) ch = 0x60;
else if (ch < 0x90) ch = 0x80;
else if (ch < 0xb0) ch = 0xa0;
else if (ch < 0xd0) ch = 0xc0;
else if (ch < 0xf0) ch = 0xe0;
else ch = 255; /* 0xff */
break;
case 9:
if (ch < 14) ch = 0; /* 0x00 */
else if (ch < 42) ch = 28;
else if (ch < 70) ch = 56;
else if (ch < 98) ch = 84;
else if (ch < 126) ch = 112;
else if (ch < 154) ch = 140;
else if (ch < 182) ch = 168;
else if (ch < 210) ch = 196;
else if (ch < 238) ch = 224;
else ch = 255; /* 0xff */
break;
case 10:
if (ch < 10) ch = 0; /* 0x00 */
else if (ch < 35) ch = 25;
else if (ch < 60) ch = 50;
else if (ch < 85) ch = 75;
else if (ch < 110) ch = 100;
else if (ch < 135) ch = 125;
else if (ch < 160) ch = 150;
else if (ch < 185) ch = 175;
else if (ch < 210) ch = 200;
else if (ch < 235) ch = 225;
else ch = 255; /* 0xff */
break;
case 11:
if (ch < 10) ch = 0; /* 0x00 */
else if (ch < 33) ch = 23;
else if (ch < 56) ch = 46;
else if (ch < 79) ch = 69;
else if (ch < 102) ch = 92;
else if (ch < 125) ch = 115;
else if (ch < 148) ch = 138;
else if (ch < 171) ch = 161;
else if (ch < 194) ch = 184;
else if (ch < 217) ch = 207;
else if (ch < 240) ch = 230;
else ch = 255; /* 0xff */
break;
}
return ch;
}
unsigned char RemapLoToHi[16] = {
LOBLACK,
LORED,
LOBROWN,
LOORANGE,
LODKGREEN,
LOGRAY,
LOLTGREEN,
LOYELLOW,
LODKBLUE,
LOPURPLE,
LOGREY,
LOPINK,
LOMEDBLUE,
LOLTBLUE,
LOAQUA,
LOWHITE};
/* Apple 2 Double Hires Format */
/* provides base address for page1 hires scanlines */
unsigned HB[]={
0x2000, 0x2400, 0x2800, 0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00,
0x2080, 0x2480, 0x2880, 0x2C80, 0x3080, 0x3480, 0x3880, 0x3C80,
0x2100, 0x2500, 0x2900, 0x2D00, 0x3100, 0x3500, 0x3900, 0x3D00,
0x2180, 0x2580, 0x2980, 0x2D80, 0x3180, 0x3580, 0x3980, 0x3D80,
0x2200, 0x2600, 0x2A00, 0x2E00, 0x3200, 0x3600, 0x3A00, 0x3E00,
0x2280, 0x2680, 0x2A80, 0x2E80, 0x3280, 0x3680, 0x3A80, 0x3E80,
0x2300, 0x2700, 0x2B00, 0x2F00, 0x3300, 0x3700, 0x3B00, 0x3F00,
0x2380, 0x2780, 0x2B80, 0x2F80, 0x3380, 0x3780, 0x3B80, 0x3F80,
0x2028, 0x2428, 0x2828, 0x2C28, 0x3028, 0x3428, 0x3828, 0x3C28,
0x20A8, 0x24A8, 0x28A8, 0x2CA8, 0x30A8, 0x34A8, 0x38A8, 0x3CA8,
0x2128, 0x2528, 0x2928, 0x2D28, 0x3128, 0x3528, 0x3928, 0x3D28,
0x21A8, 0x25A8, 0x29A8, 0x2DA8, 0x31A8, 0x35A8, 0x39A8, 0x3DA8,
0x2228, 0x2628, 0x2A28, 0x2E28, 0x3228, 0x3628, 0x3A28, 0x3E28,
0x22A8, 0x26A8, 0x2AA8, 0x2EA8, 0x32A8, 0x36A8, 0x3AA8, 0x3EA8,
0x2328, 0x2728, 0x2B28, 0x2F28, 0x3328, 0x3728, 0x3B28, 0x3F28,
0x23A8, 0x27A8, 0x2BA8, 0x2FA8, 0x33A8, 0x37A8, 0x3BA8, 0x3FA8,
0x2050, 0x2450, 0x2850, 0x2C50, 0x3050, 0x3450, 0x3850, 0x3C50,
0x20D0, 0x24D0, 0x28D0, 0x2CD0, 0x30D0, 0x34D0, 0x38D0, 0x3CD0,
0x2150, 0x2550, 0x2950, 0x2D50, 0x3150, 0x3550, 0x3950, 0x3D50,
0x21D0, 0x25D0, 0x29D0, 0x2DD0, 0x31D0, 0x35D0, 0x39D0, 0x3DD0,
0x2250, 0x2650, 0x2A50, 0x2E50, 0x3250, 0x3650, 0x3A50, 0x3E50,
0x22D0, 0x26D0, 0x2AD0, 0x2ED0, 0x32D0, 0x36D0, 0x3AD0, 0x3ED0,
0x2350, 0x2750, 0x2B50, 0x2F50, 0x3350, 0x3750, 0x3B50, 0x3F50,
0x23D0, 0x27D0, 0x2BD0, 0x2FD0, 0x33D0, 0x37D0, 0x3BD0, 0x3FD0};
unsigned char *dhrbuf=NULL;
/*
The following is logically reordered to match the lores
color order...
Repeated
Binary
Color aux1 main1 aux2 main2 Pattern
Black 00 00 00 00 0000
Magenta 08 11 22 44 0001
Dark Blue 11 22 44 08 1000
Violet 19 33 66 4C 1001
Dark Green 22 44 08 11 0100
Grey1 2A 55 2A 55 0101
Medium Blue 33 66 4C 19 1100
Light Blue 3B 77 6E 5D 1101
Brown 44 08 11 22 0010
Orange 4C 19 33 66 0011
Grey2 55 2A 55 2A 1010
Pink 5D 3B 77 6E 1011
Green 66 4C 19 33 0110
Yellow 6E 5D 3B 77 0111
Aqua 77 6E 5D 3B 1110
White 7F 7F 7F 7F 1111
*/
/* repeated binary pattern */
unsigned char dhrbits[16][28] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Black */
0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, /* Magenta */
1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0, /* Dark Blue */
1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1, /* Violet */
0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0, /* Dark Green */
0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, /* Grey1 */
1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0, /* Medium Blue */
1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1, /* Light Blue */
0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0, /* Brown */
0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1, /* Orange */
1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0, /* Grey2 */
1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1, /* Pink */
0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0, /* Green */
0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1, /* Yellow */
1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0, /* Aqua */
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; /* White */
/* the following array is based on the above */
unsigned char dhrbytes[16][4] = {
0x00,0x00,0x00,0x00,
0x08,0x11,0x22,0x44,
0x11,0x22,0x44,0x08,
0x19,0x33,0x66,0x4C,
0x22,0x44,0x08,0x11,
0x2A,0x55,0x2A,0x55,
0x33,0x66,0x4C,0x19,
0x3B,0x77,0x6E,0x5D,
0x44,0x08,0x11,0x22,
0x4C,0x19,0x33,0x66,
0x55,0x2A,0x55,0x2A,
0x5D,0x3B,0x77,0x6E,
0x66,0x4C,0x19,0x33,
0x6E,0x5D,0x3B,0x77,
0x77,0x6E,0x5D,0x3B,
0x7F,0x7F,0x7F,0x7F};
/* the following is used to remap
double lo res 4 bit colors
from bank 0 to bank 1 */
unsigned char dloauxcolor[16] = {
0,8,1,9,2,10,3,11,4,12,5,13,6,14,7,15};
/* the following is used to remap
double lo res 4 bit colors
from bank 1 to bank 0 */
unsigned char dlomaincolor[16] = {
0,2,4,6,8,10,12,14,1,3,5,7,9,11,13,15};
/* -------------------------------------------------------------- */
/* local random number generator */
/* -------------------------------------------------------------- */
/* http://stackoverflow.com/questions/7602919/how-do-i-generate-random-numbers-without-rand-function */
ushort RandomSeed = (ushort)0xACE1;
ushort my_random()
{
ushort bit = ((RandomSeed >> 0) ^ (RandomSeed >> 2) ^ (RandomSeed >> 3) ^ (RandomSeed >> 5) ) & 1;
RandomSeed = (RandomSeed >> 1) | (bit << 15);
return RandomSeed;
}
/* ------------------------------------------------------------- */
/* RandomRange */
/* returns a random number in a usuable range (1 to MaxValue) */
/* args */
/* MaxValue - the highest number we want */
/* ------------------------------------------------------------- */
int RandomRange(int iMaxValue)
{
int iRetVal;
do {
/* get random number */
iRetVal = (int)my_random();
/* get a positive value */
if (iRetVal < 0) iRetVal *= -1;
} while(iRetVal < 1);
/* use modulus of MaxValue if not in range */
if (iRetVal > iMaxValue)
iRetVal = (iRetVal%iMaxValue)+1;
return iRetVal; /* return a value in range */
}
/* convert from native format to Apple II format short integer */
ushort Motorola16(ushort val)
{
uchar buf[2];
ushort *ptr;
/* msb in smallest address */
buf[0] = (uchar) (val % 256); val = val/256;
buf[1] = (uchar) (val % 256);
ptr = (ushort *)&buf[0];
val = ptr[0];
return val;
}
/* this is also used to write width, height pairs for LGR and DLGR file headers
when the file is wider than 255 pixels */
void WriteDosHeader(FILE *fp, ushort fl, ushort fa)
{
fa = Motorola16(fa);/* file bload address - not including this header */
fl = Motorola16(fl);/* file length - not including this header */
fwrite((char *)&fa,sizeof(ushort),1,fp);
fwrite((char *)&fl,sizeof(ushort),1,fp);
}
/* upper case name for Apple II Output */
void ucase(char *str)
{
int idx;
for (idx = 0; str[idx] != (char)0; idx++) {
str[idx] = toupper(str[idx]);
}
}
/* sets up a line oriented write buffer for lores and double lo-res files */
/* this uses a different LGR and DLGR buffer organization method than Bmp2DHR */
void setlopixel(unsigned char color,int x, int y)
{
unsigned char *crt, c1, c2;
int y1, offset;
if (doublelores == 1) {
if (x%2 == 0) {
/* auxiliary memory uses a different color index value */
color = dloauxcolor[color];
/* first 160 bytes goes to auxiliary memory (even pixels) */
offset = (x/2);
}
else {
/* next 160 bytes goes to main memory (odd pixels) */
offset = 160 + (x/2);
}
}
else {
offset = x;
}
y1 = y / 2;
c2 = (unsigned char ) (color & 15);
if (y%2 == 0) {
/* even rows in low nibble */
/* mask value to preserve high nibble */
c1 = 240;
}
else {
/* odd rows in high nibble */
/* mask value to preserve low nibble */
c1 = 15;
c2 = c2 * 16;
}
/* each paired scanline is offset by 320 bytes in our write buffer */
offset += (y1 * 320);
crt = (unsigned char *)&dhrbuf[offset];
crt[0] &= c1;
crt[0] |= c2;
}
uchar getlopixel(int x, int y)
{
unsigned char *crt, color;
int y1, offset;
if (doublelores == 1) {
if (x%2 == 0) {
/* first 160 bytes goes to auxiliary memory (even pixels) */
offset = (x/2);
}
else {
/* next 160 bytes goes to main memory (odd pixels) */
offset = 160 + (x/2);
}
}
else {
offset = x;
}
y1 = y / 2;
/* each paired scanline is offset by 320 bytes in our write buffer */
offset += (y1 * 320);
crt = (unsigned char *)&dhrbuf[offset];
if (y%2 == 0) {
/* even rows in low nibble */
color = crt[0] & 15;
}
else {
/* odd rows in high nibble */
color = crt[0] >> 4;
}
if (doublelores == 1 && x%2 == 0) {
/* auxiliary memory uses a different color index value */
color = dlomaincolor[color];
}
return color;
}
ushort WriteDIBHeader(FILE *fp, ushort pixels, ushort rasters)
{
ushort outpacket;
int c;
memset((char *)&mybmp.bfi.bfType[0],0,sizeof(BMPHEADER));
/* create the info header */
mybmp.bmi.biSize = (ulong)sizeof(BITMAPINFOHEADER);
mybmp.bmi.biWidth = (ulong)pixels;
mybmp.bmi.biHeight = (ulong)rasters;
mybmp.bmi.biPlanes = 1;
mybmp.bmi.biBitCount = 24;
mybmp.bmi.biCompression = (ulong) BI_RGB;
/* BMP scanlines are padded to a multiple of 4 bytes (DWORD) */
outpacket = (ushort)mybmp.bmi.biWidth * 3;
while (outpacket%4 != 0)outpacket++;
mybmp.bmi.biSizeImage = (ulong)outpacket;
mybmp.bmi.biSizeImage *= mybmp.bmi.biHeight;
/* create the file header */
mybmp.bfi.bfType[0] = 'B';
mybmp.bfi.bfType[1] = 'M';
mybmp.bfi.bfOffBits = (ulong) sizeof(BMPHEADER);
mybmp.bfi.bfSize = mybmp.bmi.biSizeImage + mybmp.bfi.bfOffBits;
/* write the header for the output BMP */
c = fwrite((char *)&mybmp.bfi.bfType[0],sizeof(BMPHEADER),1,fp);
if (c!= 1)outpacket = 0;
return outpacket;
}
/* DHGR file input Helper Function for HGR raster format image fragments */
int read_dhr(uchar *basename)
{
FILE *fp;
uchar infile[256], lodebuf[80];
int c,y,status=INVALID,width,height,packet;
unsigned dest;
sprintf(infile,"%s.DHR",basename);
fp = fopen(infile,"rb");
if (NULL == fp && longnames == 1) {
sprintf(infile,"%s.DHR#062000",basename);
fp = fopen(infile,"rb");
}
if (NULL == fp)return INVALID;
memset(dhrbuf,0,16384);
for (;;) {
/* read 5 byte header */
c = fread(lodebuf,1,5,fp);
if (c != 5) break;
if (lodebuf[0] != 'D' || lodebuf[1] != 'H' || lodebuf[2] != 'R') break;
width = (int)lodebuf[3];
height = (int)lodebuf[4];
/* must be in a valid range */
if (width < 4 || width > 80) break;
if (height< 1 || height > 192) break;
/* set some globals for BMP output */
bmpwidth = (ushort)((width / 4) * 7);
bmpheight = (ushort) height;
status = SUCCESS;
packet = width / 2;
for (y = 0;y < height;y++) {
c = fread(lodebuf,1,width,fp);
if (c!= width) {
status = INVALID;
break;
}
dest = HB[y];
/* move to auxiliary screen memory */
memcpy((char *)&dhrbuf[dest-0x2000],(char *)&lodebuf[0],packet);
/* move to main screen memory */
memcpy((char *)&dhrbuf[dest],(char *)&lodebuf[packet],packet);
}
break;
}
fclose(fp);
return status;
}
/* DHGR file input Helper Function for AUX, BIN file pairs */
/* a double hi-res color pixel can occur at any one of 7 positions */
/* in a 4 byte block which spans aux and main screen memory */
/* the horizontal resolution is 140 pixels */
/* read 2 input files */
int read_binaux(uchar *basename)
{
FILE *fp;
uchar infile[256];
/* the bsaved images are split into two files
the first file is loaded into aux mem */
sprintf(infile,"%s.AUX",basename);
fp = fopen(infile,"rb");
if (NULL == fp && longnames == 1) {
sprintf(infile,"%s.AUX#062000",basename);
fp = fopen(infile,"rb");
}
if (NULL == fp)return INVALID;
fread(dhrbuf,1,8192,fp);
fclose(fp);
/* the second file is loaded into main mem */
sprintf(infile,"%s.BIN",basename);
fp = fopen(infile,"rb");
if (NULL == fp && longnames == 1) {
sprintf(infile,"%s.BIN#062000",basename);
fp = fopen(infile,"rb");
}
if (NULL == fp)return INVALID;
fread(&dhrbuf[8192],1,8192,fp);
fclose(fp);
return SUCCESS;
}
/* DHGR file input Helper Function for A2FC files */
/* read one input file */
int read_2fc(uchar *basename)
{
FILE *fp;
uchar infile[256];
if (longnames == 0) {
sprintf(infile,"%s.2FC",basename);
fp = fopen(infile,"rb");
}
else {
for (;;) {
/* support for longnames and ciderpress tags */
/* support for tohgr output */
if (tohgr == 0)
sprintf(infile,"%s.2FC",basename);
else
sprintf(infile,"%s.dhgr",basename);
fp = fopen(infile,"rb");
if (NULL != fp)break;
if (tohgr == 0) {
if (mono == 0) sprintf(infile,"%s.A2FC",basename);
else sprintf(infile,"%s.A2FM",basename);
}
else {
sprintf(infile,"%s.DHGR",basename);
}
fp = fopen(infile,"rb");
if (NULL != fp)break;
if (tohgr == 0)
sprintf(infile,"%s.2FC#062000",basename);
else
sprintf(infile,"%s.dhgr#062000",basename);
fp = fopen(infile,"rb");
if (NULL != fp)break;
if (tohgr == 0) {
if (mono == 0) sprintf(infile,"%s.A2FC#062000",basename);
else sprintf(infile,"%s.A2FM#062000",basename);
}
else {
sprintf(infile,"%s.DHGR#062000",basename);
}
fp = fopen(infile,"rb");
break;
}
}
if (NULL == fp)return INVALID;
fread(dhrbuf,1,16384,fp);
fclose(fp);
return SUCCESS;
}
/* Color DHGR Pixel-Mapping Helper Function */
/* returns the Apple II Double Hi-res drawcolor 0-15 */
/* a double hi-res color pixel can occur at any one of 7 positions */
/* in a 4 byte block which spans aux and main screen memory */
/* the horizontal resolution is 140 pixels */
int dhrgetpixel(int x,int y)
{
int xoff, pattern, idx;
unsigned char *ptraux, *ptrmain,c1, c2, d1, d2;
if (x < 0 || x > 139 || y < 0 || y > 192) return INVALID;
pattern = (x%7);
xoff = HB[y] + ((x/7) * 2);
ptraux = (unsigned char *) &dhrbuf[xoff-0x2000];
ptrmain = (unsigned char *) &dhrbuf[xoff];
switch(pattern)
{
/* left this here for reference
unsigned char dhrpattern[7][4] = {
0,0,0,0,
0,0,0,1,
1,1,1,1,
1,1,2,2,
2,2,2,2,
2,3,3,3,
3,3,3,3};
*/
/* compare colors in the input file to color patterns and return drawcolor */
/* somewhat inelegant but lazy to read and debug if a problem */
case 0: c1 = ptraux[0] &0x0f;
for (idx = 0; idx < 16; idx++) {
d1 = dhrbytes[idx][0] & 0x0f;
if (d1 == c1) return idx;
}
break;
case 1: c1 = ptraux[0] & 0x70;
c2 = ptrmain[0] & 0x01;
for (idx = 0; idx < 16; idx++) {
d1 = dhrbytes[idx][0] & 0x70;
d2 = dhrbytes[idx][1] & 0x01;
if (d1 == c1 && d2 == c2) return idx;
}
break;
case 2: c1 = ptrmain[0] & 0x1e;
for (idx = 0; idx < 16; idx++) {
d1 = dhrbytes[idx][1] & 0x1e;
if (d1 == c1) return idx;
}
break;
case 3: c1 = ptrmain[0] & 0x60;
c2 = ptraux[1] & 0x03;
for (idx = 0; idx < 16; idx++) {
d1 = dhrbytes[idx][1] & 0x60;
d2 = dhrbytes[idx][2] & 0x03;
if (d1 == c1 && d2 == c2) return idx;
}
break;
case 4: c1 = ptraux[1] & 0x3c;
for (idx = 0; idx < 16; idx++) {
d1 = dhrbytes[idx][2] & 0x3c;
if (d1 == c1) return idx;
}
break;
case 5: c1 = ptraux[1] & 0x40;
c2 = ptrmain[1] & 0x07;
for (idx = 0; idx < 16; idx++) {
d1 = dhrbytes[idx][2] & 0x40;
d2 = dhrbytes[idx][3] & 0x07;
if (d1 == c1 && d2 == c2) return idx;
}
break;
case 6: c1 = ptrmain[1] & 0x78;
for (idx = 0; idx < 16; idx++) {
d1 = dhrbytes[idx][3] & 0x78;
if (d1 == c1) return idx;
}
break;
}
return INVALID;
}
ushort WriteVbmpHeader(FILE *fp)
{
ushort outpacket;
int c, i, j;
/* BMP scanlines are padded to a multiple of 4 bytes (DWORD) */
outpacket = (ushort)72;
if (mono != 0) {
c = fwrite(mono192,1,sizeof(mono192),fp);
if (c!= sizeof(mono192))return 0;
return outpacket;
}
memset((char *)&mybmp.bfi.bfType[0],0,sizeof(BMPHEADER));
/* create the info header */
mybmp.bmi.biSize = (ulong)40;
mybmp.bmi.biWidth = (ulong)140;
mybmp.bmi.biHeight = (ulong)192;
mybmp.bmi.biPlanes = 1;
mybmp.bmi.biBitCount = 4;
mybmp.bmi.biCompression = (ulong) BI_RGB;
mybmp.bmi.biSizeImage = (ulong)outpacket;
mybmp.bmi.biSizeImage *= mybmp.bmi.biHeight;
/* create the file header */
mybmp.bfi.bfType[0] = 'B';
mybmp.bfi.bfType[1] = 'M';
mybmp.bfi.bfOffBits = (ulong) sizeof(BMPHEADER) + sizeof(RGBQUAD) * 16;
mybmp.bfi.bfSize = mybmp.bmi.biSizeImage + mybmp.bfi.bfOffBits;
/* write the header for the output BMP */
c = fwrite((char *)&mybmp.bfi.bfType[0],sizeof(BMPHEADER),1,fp);
if (c!= 1)return 0;
for (i=0;i<16;i++) {
j = RemapLoToHi[i];
sbmp[i].rgbRed = rgbArray[j][0];
sbmp[i].rgbGreen = rgbArray[j][1];
sbmp[i].rgbBlue = rgbArray[j][2];
sbmp[i].rgbReserved = 0;
}
/* write the palette for the output bmp */
c = fwrite((char *)&sbmp[0].rgbBlue, sizeof(RGBQUAD)*16,1,fp);
if (c!= 1)return 0;
return outpacket;
}
/* writes VBMP compatible 140 x 192 x 16 color bmp or VBMP compatible 560 x 192 monochrome bmp */
int WriteVBMPFile(unsigned char *vbmpfile)
{
FILE *fp;
uchar ch;
int x,x1,y,y2,idx,j,packet=72;
fp = fopen(vbmpfile,"wb");
if (fp == NULL) {
printf("Error opening %s for writing!\n",vbmpfile);
return INVALID;
}
if (WriteVbmpHeader(fp) == 0) {
fclose(fp);
remove(vbmpfile);
printf("Error writing header to %s!\n",vbmpfile);
return INVALID;
}
memset(&bmpscanline[0],0,packet);
/* write 4 bit packed scanlines */
/* remap from LORES color order to DHGR color order */
/* VBMP does not use the colors in the palette, just the color order */
y2 = 191;
for (y = 0; y< 192; y++) {
for (x = 0, x1=0; x < 140; x++) {
if (x%2 == 0) {
idx = dhrgetpixel(x,y2);
/* range check */
if (idx < 0 || idx > 15)idx = 0; /* default black */
j = RemapLoToHi[idx];
ch = (uchar)j << 4;
}
else {
idx = dhrgetpixel(x,y2);
/* range check */
if (idx < 0 || idx > 15)idx = 0; /* default black */
j = RemapLoToHi[idx];
bmpscanline[x1] = ch | (uchar)j; x1++;
}
}
fwrite((char *)&bmpscanline[0],1,packet,fp);
y2 -= 1;
}
fclose(fp);
return SUCCESS;
}
/* Color Output Helper Function */
int save_to_bmp24(uchar *basename)
{
FILE *fp;
uchar outfile[256], tempr, tempg, tempb;
int x,x1,y,y2,idx,packet,xoffset=0,yoffset=0;
sprintf(outfile,"%s.bmp",basename);
if (vbmp == 1) return WriteVBMPFile(outfile);
if (frag == 1) {
/* create BMP image fragment from full-screen Apple II input */
dhr = 1;
bmpwidth = fragwidth;
bmpheight = fragheight;
xoffset = fragx;
yoffset = fragy;
}
fp = fopen(outfile,"wb");
if (NULL == fp)return INVALID;
/* write rgb triples and double each pixel to preserve the aspect ratio */
if (doublepixel == 1) {
/* write header for 280 x 192 x 24 bit bmp */
if (dhr == 1) packet = (int)WriteDIBHeader(fp,bmpwidth*2,bmpheight);
else fwrite(BMP_header,1,sizeof(BMP_header),fp);
}
else {
/* write header for 140 x 192 x 24 bit bmp */
if (dhr == 1) packet = (int)WriteDIBHeader(fp,bmpwidth,bmpheight);
else fwrite(BMP140_header,1,sizeof(BMP140_header),fp);
}
if (dhr == 1) {
memset(&bmpscanline[0],0,840);
y2 = (bmpheight) - 1;
for (y = 0; y< bmpheight; y++) {
for (x = 0, x1=0; x < bmpwidth; x++) {
idx = dhrgetpixel(x+xoffset,y2+yoffset);
if (idx < 0 || idx > 15)idx = 0;
tempr = rgbArray[idx][0];
tempg = rgbArray[idx][1];
tempb = rgbArray[idx][2];
bmpscanline[x1] = tempb; x1++;
bmpscanline[x1] = tempg; x1++;
bmpscanline[x1] = tempr; x1++;
if (doublepixel == 1) {
bmpscanline[x1] = tempb; x1++;
bmpscanline[x1] = tempg; x1++;
bmpscanline[x1] = tempr; x1++;
}
}
fwrite((char *)&bmpscanline[0],1,packet,fp);
y2 -= 1;
}
}
else {
y2 = 191;
for (y = 0; y< 192; y++) {
for (x = 0; x < 140; x++) {
idx = dhrgetpixel(x,y2);
/* range check */
if (idx < 0 || idx > 15)idx = 0; /* default to black */
tempr = rgbArray[idx][0];
tempg = rgbArray[idx][1];
tempb = rgbArray[idx][2];
/* reverse order */
fputc(tempb, fp);
fputc(tempg, fp);
fputc(tempr, fp);
if (doublepixel == 1) {
/* double-up */
fputc(tempb, fp);
fputc(tempg, fp);
fputc(tempr, fp);
}
}
y2 -= 1;
}
}
fclose(fp);
return SUCCESS;
}
/* encodes apple II dhgr scanline into buffer */
int applewinbits(int y)
{
int xoff,idx,jdx;
unsigned char *ptraux, *ptrmain, bits[7];
xoff = HB[y];
ptraux = (unsigned char *) &dhrbuf[xoff-0x2000];
ptrmain = (unsigned char *) &dhrbuf[xoff];
xoff = 0;
for (idx = 0; idx < 40; idx++) {
for (jdx = 0; jdx < 7; jdx++) {
bits[jdx] = bmpscanline[xoff]; xoff++;
}
ptraux[idx] = (bits[6]<<6|bits[5]<<5|bits[4]<<4|
bits[3]<<3|bits[2]<<2|bits[1]<<1|bits[0]);
for (jdx = 0; jdx < 7; jdx++) {
bits[jdx] = bmpscanline[xoff]; xoff++;
}
ptrmain[idx] = (bits[6]<<6|bits[5]<<5|bits[4]<<4|
bits[3]<<3|bits[2]<<2|bits[1]<<1|bits[0]);
}
return SUCCESS;
}
/* routines for optional SHR grey-scaling using hsl */
/* by default, average RGB is used */
/*
http://www.vbaccelerator.com/home/VB/Code/vbMedia/Colour_Models/Hue__Luminance_and_Saturation/article.asp
*/
/* Creative Commons Section Start */
float Minimum(float rr, float rg, float rb)
{
if (rr < rg) {
if (rr < rb)return rr;
return rb;
}
if (rb < rg) return rb;
return rg;
}
float Maximum(float rr, float rg, float rb)
{
if (rr > rg) {
if (rr > rb)return rr;
return rb;
}
if (rb > rg) return rb;
return rg;
}
void rgb2hsl(uchar r,uchar g,uchar b,float *h,float *s,float *l)
{
float rr,rg,rb,min,max,delta;
rr = (float) r;
rg = (float) g;
rb = (float) b;
rr /= 255;
rg /= 255;
rb /= 255;
max = Maximum(rr, rg, rb);
min = Minimum(rr, rg, rb);
l[0] = (max + min) / 2;
if (max == min) {
/* achromatic - grey */
s[0] = h[0] = (float)0.0;
}
else {
/* chromatic - colors */
if (l[0] <= 0.5) s[0] = (max - min) / (max + min);
else s[0] = (max - min) / (2.0 - max - min);
delta = max - min;
if (rr == max) h[0] = (rg - rb) / delta;
else if (rg == max) h[0] = 2.0 + (rb - rr) / delta;
else if (rb == max) h[0] = 4.0 + (rr - rg) / delta;
}
}
void hsl2rgb(float h,float s,float l,uchar *r,uchar *g,uchar *b)
{
float rr,rg,rb,min,max;
if (s == 0) {
/* achromatic - greyscale */
rr = rg = rb = l;
}
else {
/* chromatic - colors */
if (l <= 0.5) min = l * (1.0 - s);
else min = l - s * (1.0 - l);
max = 2.0 * l - min;
if (h < 1) {
rr = max;
if (h < 0) {
rg = min;
rb = rg - h * (max - min);
}
else {
rb = min;
rg = h * (max - min) + rb;
}
}
else if (h < 3) {
rg = max;
if (h < 2) {
rb = min;
rr = rb - (h - 2) * (max - min);
}
else {
rr = min;
rb = (h - 2.0) * (max - min) + rr;
}
}
else {
rb = max;
if (h < 4) {
rr = min;
rg = rr - (h - 4) * (max - min);
}
else {
rg = min;
rr = (h - 4.0) * (max - min) + rg;
}
}
}
r[0] = (uchar)(float)(rr * 255);
g[0] = (uchar)(float)(rg * 255);
b[0] = (uchar)(float)(rb * 255);
}
/* Creative Commons Section End */
/* set luma to different values for closest color */
/* read this first - https://en.wikipedia.org/wiki/YCbCr */
/* also read https://en.wikipedia.org/wiki/Color_space */
/* also read https://en.wikipedia.org/wiki/RGB_color_space */
int lumaREQ = 601, lumaRED = 299, lumaGREEN = 587, lumaBLUE = 114;
double dlumaRED, dlumaGREEN, dlumaBLUE;
/* strip line feeds from ascii file lines... */
void nocr(char *ptr) {
int idx;
for (idx = 0; ptr[idx] != 0; idx++)
if (ptr[idx] == LFEED || ptr[idx] == CRETURN || ptr[idx] == '#')
ptr[idx] = 0;
}
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<EFBFBD>B<EFBFBD> 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;
}
}
double rgbLuma[16], rgbDouble[16][3];
int brooksline = 999;
/* intialize the values for the current palette */
void InitDoubleArrays()
{
int i;
double dr, dg, db;
/* array for matching closest color in palette */
for (i=0;i<16;i++) {
rgbDouble[i][0] = dr = (double) rgbArray[i][0];
rgbDouble[i][1] = dg = (double) rgbArray[i][1];
rgbDouble[i][2] = db = (double) rgbArray[i][2];
rgbLuma[i] = (dr*lumaRED + dg*lumaGREEN + db*lumaBLUE) / (255.0*1000);
}
}
/* for SHR output */
/* intialize the closest color palette for each scanline */
void InitDoubleLineArrays(int y)
{
int i;
double dr, dg, db;
/* array for matching closest color in palette */
for (i=0;i<16;i++) {
rgbDouble[i][0] = dr = (double) rgbArrays[y][i][0];
rgbDouble[i][1] = dg = (double) rgbArrays[y][i][1];
rgbDouble[i][2] = db = (double) rgbArrays[y][i][2];
rgbLuma[i] = (dr*lumaRED + dg*lumaGREEN + db*lumaBLUE) / (255.0*1000);
}
brooksline = y;
}
void InitDoubleLine256Arrays(int idx)
{
int i;
double dr, dg, db;
/* array for matching closest color in palette */
for (i=0;i<16;i++) {
rgbDouble[i][0] = dr = (double) rgb256Arrays[idx][i][0];
rgbDouble[i][1] = dg = (double) rgb256Arrays[idx][i][1];
rgbDouble[i][2] = db = (double) rgb256Arrays[idx][i][2];
rgbLuma[i] = (dr*lumaRED + dg*lumaGREEN + db*lumaBLUE) / (255.0*1000);
}
for (i=0,brooksline=0;i<200;i++) {
if (idx == (int)mypic.scb[i]) {
brooksline = i;
break;
}
}
}
double globaldistance = 0.0, indexdistance = 0.0, brooksdistance = 0.0;
/* use CCIR 601 luminosity to get color distance value */
uchar GetColorDistance(uchar r, uchar g, uchar b, uchar idx)
{
uchar drawcolor, i;
double dr, dg, db, diffR, diffG, diffB, luma, lumadiff, distance, prevdistance;
indexdistance = 0.0;
/* 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++) {
if (i<15) {
if (i != idx) continue;
}
/* 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*dlumaGREEN)*0.75
+ lumadiff*lumadiff;
/* if distance is smaller use this index */
if (distance < prevdistance) {
prevdistance = distance;
drawcolor = (uchar)i;
}
}
indexdistance = prevdistance;
return drawcolor;
}
/* 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;
}