summaryrefslogtreecommitdiff
path: root/app/help/mkshg.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/help/mkshg.c')
-rw-r--r--app/help/mkshg.c455
1 files changed, 455 insertions, 0 deletions
diff --git a/app/help/mkshg.c b/app/help/mkshg.c
new file mode 100644
index 0000000..4c708fa
--- /dev/null
+++ b/app/help/mkshg.c
@@ -0,0 +1,455 @@
+#include <stdio.h>
+#include <string.h>
+#include "readpng.h"
+
+#define PROGNAME "mkshg"
+
+
+int verbose = 0;
+int dmpcolortab = 0;
+int dmpimage = 0;
+
+#define MAXRUNLEN (2)
+
+typedef struct {
+ unsigned char id0, id1, id2;
+ unsigned short x, y, w, h;
+ long hash;
+ char * name;
+ char * context;
+ } hotspot_t;
+
+int samecolor( long color1, long color2 )
+{
+ long c1, c2;
+ int i;
+ for ( i=0; i<3; i++ ) {
+ c1 = (color1&0xFF);
+ c2 = (color2&0xFF);
+ if ( c1 != c2 ) {
+ if ( c1 == 0xFF || c2 == 0xFF ) return FALSE;
+ c1 = (c1+1)&0xFE;
+ c2 = (c2+1)&0xFE;
+ if ( c1 != c2 ) return FALSE;
+ }
+ color1 >>= 8;
+ color2 >>= 8;
+ }
+ return TRUE;
+}
+
+void conv24to8( long * colorTab, char * buff, unsigned long channels, unsigned long width24, unsigned long width8, unsigned long height )
+{
+ long * lastColor, *cp;
+ long color;
+ char * ip;
+ char *op;
+ unsigned long h, w;
+ memset( colorTab, 0, 1024 );
+ lastColor = colorTab;
+ *lastColor++ = 0xC0C0C0;
+ *lastColor++ = 0xFFFFFF;
+ *lastColor++ = 0x808080;
+ *lastColor++ = 0x000000;
+ op = buff;
+ for (h=0; h<height; h++) {
+ ip = buff+(width24*h);
+ op = buff+(width8*h);
+ for (w=0; w<width24; w+=channels,op++ ) {
+ color = ((long)(unsigned char)(ip[0]))<<16;
+ color += ((long)(unsigned char)(ip[1]))<<8;
+ color += ((long)(unsigned char)(ip[2]));
+ ip += channels;
+ for ( cp=colorTab; cp<lastColor; cp++ ) {
+ if ( samecolor( color, *cp ) ) {
+ *op = (char)(cp-colorTab);
+ goto nextPixel;
+ }
+ }
+ if (lastColor < &colorTab[256]) {
+ *op = (char)(lastColor-colorTab);
+ *lastColor++ = color;
+ } else {
+ *op = 0;
+ }
+nextPixel:
+ if ( dmpimage ) {
+ char c;
+ if ( *op < 10 )
+ printf( "%c", '0'+*op );
+ else if ( *op < 10+26 )
+ printf( "%c", *op-10+'a' );
+ else if ( *op < 10+26+26 )
+ printf( "%c", *op-10-26+'A' );
+ else
+ printf( "\%2.2x", *op );
+ }
+ }
+ *op++ = 0;
+ *op++ = 0;
+ if ( dmpimage )
+ printf( "00\n" );
+ }
+if ( dmpcolortab ) {
+ int i;
+ for ( i=0; i<lastColor-colorTab; i++ ) {
+ printf( "C[%3d] %6.6lx\n", i, colorTab[i] );
+ }
+}
+}
+
+
+void compress_data(
+ unsigned char * ip0,
+ unsigned long isize,
+ unsigned char * op0,
+ unsigned long * osize )
+{
+ unsigned char * ip=ip0, * op=op0;
+ int runlen, norunlen, chunk;
+ norunlen = 0;
+ while ( ip < ip0+isize ) {
+ for ( runlen=0; ip+runlen<ip0+isize && ip[0]==ip[runlen]; runlen++ );
+ if ( runlen > MAXRUNLEN || runlen == 0 ) {
+ while ( norunlen > 0 ) {
+ if ( norunlen > 0x7F )
+ chunk = 0x7F;
+ else
+ chunk = norunlen;
+ *op++ = 0x80|chunk;
+ memcpy( op, ip-norunlen, chunk );
+ op += chunk;
+ norunlen -= chunk;
+ }
+ while ( runlen > MAXRUNLEN ) {
+ if ( runlen > 0x7F )
+ chunk = 0x7F;
+ else
+ chunk = runlen;
+ *op++ = chunk;
+ *op++ = *ip;
+ ip += chunk;
+ runlen -= chunk;
+ }
+ } else {
+ norunlen += runlen;
+ ip += runlen;
+ }
+ }
+ *osize = op-op0;
+}
+
+
+void writeculong( FILE * shgF, unsigned long value )
+{
+ unsigned short tmp;
+ if ( value > 0x7FFF ) {
+ tmp = (unsigned short)((value&0x7FFF)<<1)+1;
+ fwrite( &tmp, 2, 1, shgF );
+ tmp = (unsigned short)(value>>15);
+ fwrite( &tmp, 2, 1, shgF );
+ } else {
+ tmp = (unsigned short)(value<<1);
+ fwrite( &tmp, 2, 1, shgF );
+ }
+}
+
+void writecushort( FILE * shgF, unsigned short value )
+{
+ unsigned char tmp;
+ if ( value > 0x7F ) {
+ tmp = (unsigned short)((value&0x7F)<<1)+1;
+ fwrite( &tmp, 1, 1, shgF );
+ tmp = (unsigned short)(value>>7);
+ fwrite( &tmp, 1, 1, shgF );
+ } else {
+ tmp = (unsigned short)(value<<1);
+ fwrite( &tmp, 1, 1, shgF );
+ }
+}
+
+void writeShgPic(
+ FILE * shgF,
+ unsigned long width,
+ unsigned long width8,
+ unsigned long height,
+ long colorTab[256],
+ unsigned char * data,
+ unsigned short hotspotcnt,
+ hotspot_t * hotspots )
+{
+ short int pictype, packmethod;
+ unsigned long xdpi, ydpi, colorsused, colorsimportant, compressedsize, hotspotsize, compressoffset, hotspotoffset;
+ unsigned short planes, bitcount;
+ unsigned char * compressed_data;
+ unsigned int start_off, offset_off, off;
+ unsigned short inx;
+ unsigned char one = 1;
+ unsigned long macrosize = 0;
+
+ pictype = 6;
+ packmethod = 1;
+ xdpi = ydpi = 96;
+ planes = 1;
+ bitcount = 8;
+ colorsused = 256;
+ colorsimportant = 256;
+ hotspotsize = (hotspotcnt?7:0);
+ hotspotoffset = 0;
+ compressed_data = (unsigned char *)malloc( width8*height );
+ compress_data( data, width8*height, compressed_data, &compressedsize );
+ for ( inx=0; inx<hotspotcnt; inx++ )
+ hotspotsize += 15+strlen(hotspots[inx].name)+1+strlen(hotspots[inx].context)+1;
+
+ start_off = ftell( shgF );
+ fwrite( &pictype, 1, 1, shgF );
+ fwrite( &packmethod, 1, 1, shgF );
+ writeculong( shgF, xdpi );
+ writeculong( shgF, ydpi );
+ writecushort( shgF, planes );
+ writecushort( shgF, bitcount );
+ writeculong( shgF, width );
+ writeculong( shgF, height );
+ writeculong( shgF, colorsused );
+ writeculong( shgF, colorsimportant );
+ writeculong( shgF, compressedsize );
+ writeculong( shgF, hotspotsize );
+ offset_off = ftell( shgF );
+ compressoffset = offset_off-start_off+8+colorsused*4;
+ fwrite( &compressoffset, 4, 1, shgF );
+ fwrite( &hotspotoffset, 4, 1, shgF );
+ if ( verbose )
+ printf( "TY=%d, PK=%d, XD=%ld, YD=%ld, PL=%d, BC=%d, W=%ld, H=%ld, CU=%ld, CI=%ld, CS=%ld, HS=%ld, CO=%ld, HO=%ld\n",
+ pictype, packmethod, xdpi, ydpi, planes, bitcount, width, height, colorsused, colorsimportant, compressedsize, hotspotsize, compressoffset, hotspotoffset );
+ fwrite( colorTab, colorsused, 4, shgF );
+ fwrite( compressed_data, compressedsize, 1, shgF );
+ if ( hotspotcnt>0 ) {
+ hotspotoffset = ftell( shgF ) - start_off;
+ fwrite( &one, 1, 1, shgF );
+ fwrite( &hotspotcnt, 2, 1, shgF );
+ fwrite( &macrosize, 4, 1, shgF );
+ for ( inx=0; inx<hotspotcnt; inx++ ) {
+ fwrite( &hotspots[inx].id0, 1, 1, shgF );
+ fwrite( &hotspots[inx].id1, 1, 1, shgF );
+ fwrite( &hotspots[inx].id2, 1, 1, shgF );
+ fwrite( &hotspots[inx].x, 2, 1, shgF );
+ fwrite( &hotspots[inx].y, 2, 1, shgF );
+ fwrite( &hotspots[inx].w, 2, 1, shgF );
+ fwrite( &hotspots[inx].h, 2, 1, shgF );
+ fwrite( &hotspots[inx].hash, 4, 1, shgF );
+ }
+ for ( inx=0; inx<hotspotcnt; inx++ ) {
+ fwrite( hotspots[inx].name, strlen(hotspots[inx].name)+1, 1, shgF );
+ fwrite( hotspots[inx].context, strlen(hotspots[inx].context)+1, 1, shgF );
+ }
+ fseek( shgF, offset_off+4, SEEK_SET );
+ fwrite( &hotspotoffset, 4, 1, shgF );
+ }
+
+ free( compressed_data );
+}
+
+
+signed char hashTable[256]=
+{
+ '\x00', '\xD1', '\xD2', '\xD3', '\xD4', '\xD5', '\xD6', '\xD7',
+ '\xD8', '\xD9', '\xDA', '\xDB', '\xDC', '\xDD', '\xDE', '\xDF',
+ '\xE0', '\xE1', '\xE2', '\xE3', '\xE4', '\xE5', '\xE6', '\xE7',
+ '\xE8', '\xE9', '\xEA', '\xEB', '\xEC', '\xED', '\xEE', '\xEF',
+ '\xF0', '\x0B', '\xF2', '\xF3', '\xF4', '\xF5', '\xF6', '\xF7',
+ '\xF8', '\xF9', '\xFA', '\xFB', '\xFC', '\xFD', '\x0C', '\xFF',
+ '\x0A', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
+ '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F',
+ '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
+ '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D', '\x1E', '\x1F',
+ '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
+ '\x28', '\x29', '\x2A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0D',
+ '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
+ '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D', '\x1E', '\x1F',
+ '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
+ '\x28', '\x29', '\x2A', '\x2B', '\x2C', '\x2D', '\x2E', '\x2F',
+ '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57',
+ '\x58', '\x59', '\x5A', '\x5B', '\x5C', '\x5D', '\x5E', '\x5F',
+ '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
+ '\x68', '\x69', '\x6A', '\x6B', '\x6C', '\x6D', '\x6E', '\x6F',
+ '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
+ '\x78', '\x79', '\x7A', '\x7B', '\x7C', '\x7D', '\x7E', '\x7F',
+ '\x80', '\x81', '\x82', '\x83', '\x0B', '\x85', '\x86', '\x87',
+ '\x88', '\x89', '\x8A', '\x8B', '\x8C', '\x8D', '\x8E', '\x8F',
+ '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
+ '\x98', '\x99', '\x9A', '\x9B', '\x9C', '\x9D', '\x9E', '\x9F',
+ '\xA0', '\xA1', '\xA2', '\xA3', '\xA4', '\xA5', '\xA6', '\xA7',
+ '\xA8', '\xA9', '\xAA', '\xAB', '\xAC', '\xAD', '\xAE', '\xAF',
+ '\xB0', '\xB1', '\xB2', '\xB3', '\xB4', '\xB5', '\xB6', '\xB7',
+ '\xB8', '\xB9', '\xBA', '\xBB', '\xBC', '\xBD', '\xBE', '\xBF',
+ '\xC0', '\xC1', '\xC2', '\xC3', '\xC4', '\xC5', '\xC6', '\xC7',
+ '\xC8', '\xC9', '\xCA', '\xCB', '\xCC', '\xCD', '\xCE', '\xCF'
+};
+
+void readHotspots(
+ FILE * inF,
+ unsigned short * hotspotcnt,
+ hotspot_t * * hotspotptr )
+{
+ hotspot_t hs, *hs_p;
+ int x, y;
+ unsigned short hs_c;
+ char type[80];
+ char name[80];
+ char line[256], *context;
+ int off;
+ int rc;
+
+ hs_c = 0;
+ hs_p = NULL;
+ while ( fgets( line, sizeof line, inF ) != NULL ) {
+ rc=sscanf( line, "%s %hd %hd %hd %hd %n", type, &x, &y, &hs.w, &hs.h, &off );
+ if ( hs_c > 0 ) {
+ if ( x < 0 )
+ x = ((int)hs_p[hs_c-1].x) - x;
+ if ( y < 0 )
+ y = ((int)hs_p[hs_c-1].y) - y;
+ }
+ hs.x = (unsigned short)x;
+ hs.y = (unsigned short)y;
+ if ( rc != 5 )
+ fprintf( stderr, "Invalid hotspot syntax: %s", line );
+ if ( strcasecmp( type, "jump" ) == 0 ) {
+ hs.id0 = 0xe7;
+ hs.id1 = 0x04;
+ hs.id2 = 0x00;
+ } else if ( strcasecmp( type, "popup" ) == 0 ) {
+ hs.id0 = 0xe6;
+ hs.id1 = 0x04;
+ hs.id2 = 0x00;
+ } else if ( strcasecmp( type, "ignore" ) == 0 ) {
+ continue;
+ } else {
+ fprintf( stderr, "Invalid hotspot type: %s", line );
+ continue;
+ }
+ sprintf( name, "Hotspot %d", hs_c+1 );
+ hs.name = strdup( name );
+ context = line+off;
+ off = strlen( context );
+ if ( context[off-1] == '\n' ) context[off-1] = 0;
+ hs.context = strdup( context );
+ for (hs.hash=0; *context; context++ )
+ hs.hash = (hs.hash*43)+hashTable[(unsigned char)*context];
+ hs_c++;
+ hs_p = (hotspot_t*)realloc( hs_p, hs_c * sizeof hs );
+ hs_p[hs_c-1] = hs;
+ }
+ *hotspotcnt = hs_c;
+ *hotspotptr = hs_p;
+}
+
+
+void PngToShg(
+ char * pngFile,
+ char * shgFile )
+{
+ FILE * pngF, * shgF;
+ int rc;
+ unsigned long image_width, image_height, image_rowbytes, width8, h;
+ int image_channels;
+ unsigned char * image_data;
+ double display_exponent = 1.0;
+
+ long size, fileSize, maxRecSize;
+ long colorTab[256];
+
+ short int magic;
+ short int piccnt;
+ long int picoff[1];
+
+ unsigned short hotspotcnt;
+ hotspot_t * hotspotptr;
+
+ pngF = fopen( pngFile, "r" );
+ if ( pngF == NULL ) {
+ perror( pngFile );
+ return;
+ }
+ shgF = fopen( shgFile, "w" );
+ if ( shgF == NULL ) {
+ perror( shgFile );
+ return;
+ }
+ if ((rc = readpng_init(pngF, &image_width, &image_height)) != 0) {
+ switch (rc) {
+ case 1:
+ fprintf(stderr, PROGNAME
+ ": [%s] is not a PNG file: incorrect signature\n",
+ pngFile);
+ break;
+ case 2:
+ fprintf(stderr, PROGNAME
+ ": [%s] has bad IHDR (libpng longjmp)\n",
+ pngFile);
+ break;
+ case 4:
+ fprintf(stderr, PROGNAME ": insufficient memory\n");
+ break;
+ default:
+ fprintf(stderr, PROGNAME
+ ": unknown readpng_init() error\n");
+ break;
+ }
+ return;
+ }
+
+ image_data = readpng_get_image(display_exponent, &image_channels, &image_rowbytes);
+ width8 = ((image_width+3)/4)*4;
+ size = width8*image_height;
+ fileSize = (size+1024)/2 + 70;
+ maxRecSize = (size+1024)/2 + 34;
+
+ conv24to8( colorTab, image_data, image_channels, image_width*image_channels, width8, image_height );
+
+ magic = 0x706c;
+ piccnt = 1;
+ picoff[0] = 8;
+ fwrite( &magic, 2, 1, shgF );
+ fwrite( &piccnt, 2, 1, shgF );
+ fwrite( picoff, 4, piccnt, shgF );
+ readHotspots( stdin, &hotspotcnt, &hotspotptr );
+ writeShgPic( shgF, image_width, width8, image_height, colorTab, image_data, hotspotcnt, hotspotptr );
+ if ( hotspotptr )
+ free( hotspotptr );
+
+ readpng_cleanup(FALSE);
+ fclose( pngF );
+ fclose( shgF );
+ free( image_data );
+
+}
+
+int main( argc, argv )
+int argc; char * argv[];
+{
+ while ( argc > 1 && argv[1][0] == '-' ) {
+ switch ( argv[1][1] ) {
+ case 'v':
+ verbose++;
+ break;
+ case 'c':
+ dmpcolortab++;
+ break;
+ case 'i':
+ dmpimage++;
+ break;
+ default:
+ fprintf( stderr, "Unknown option: %s\n", argv[1] );
+ exit(1);
+ }
+ argv++;
+ argc--;
+ }
+ if ( argc != 3 ) {
+ fprintf( stderr, "Usage: mkshg [-v] [-c] infile.png outfile.shg\n" );
+ exit(1);
+ }
+
+ PngToShg( argv[1], argv[2] );
+}