add support for reading HP-48 Grob format

This commit is contained in:
Thomas BERNARD 2019-07-13 19:10:45 +02:00 committed by Thomas Bernard
parent 911ad97646
commit 0cea439da9
No known key found for this signature in database
GPG Key ID: 0FF11B67A5C0863C
4 changed files with 150 additions and 6 deletions

View File

@ -155,6 +155,7 @@ enum FILE_FORMATS
FORMAT_MOTO, ///< Thomson MO/TO computers pictures FORMAT_MOTO, ///< Thomson MO/TO computers pictures
FORMAT_HGR, ///< Apple II HGR and DHGR FORMAT_HGR, ///< Apple II HGR and DHGR
FORMAT_TIFF, ///< Tagged Image File Format FORMAT_TIFF, ///< Tagged Image File Format
FORMAT_GRB, ///< HP-48 Grob
FORMAT_MISC, ///< Must be last of enum: others formats recognized by SDL_image (or recoil) FORMAT_MISC, ///< Must be last of enum: others formats recognized by SDL_image (or recoil)
FORMAT_CLIPBOARD ///< To load/save from/to Clipboard FORMAT_CLIPBOARD ///< To load/save from/to Clipboard
}; };

View File

@ -2,7 +2,7 @@
*/ */
/* Grafx2 - The Ultimate 256-color bitmap paint program /* Grafx2 - The Ultimate 256-color bitmap paint program
Copyright 2018 Thomas Bernard Copyright 2018-2019 Thomas Bernard
Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
Grafx2 is free software; you can redistribute it and/or Grafx2 is free software; you can redistribute it and/or
@ -175,5 +175,9 @@ void Load_TIFF_from_memory(T_IO_Context *, const void *, unsigned long);
void Save_TIFF_to_memory(T_IO_Context *, void * *, unsigned long *); void Save_TIFF_to_memory(T_IO_Context *, void * *, unsigned long *);
#endif #endif
// -- HP-48 Grob ------------------------------------------------------------
void Test_GRB(T_IO_Context *, FILE *);
void Load_GRB(T_IO_Context *);
/// @} /// @}
#endif #endif

View File

@ -119,6 +119,7 @@ const T_Format File_formats[] = {
"gpx;" "gpx;"
"cpc;scr;win;" "cpc;scr;win;"
"hgr;dhgr;" "hgr;dhgr;"
"grb;grob;"
"tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico;ic2;cur;cm5;pph;info;flc;bin;map"}, "tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico;ic2;cur;cm5;pph;info;flc;bin;map"},
{FORMAT_ALL_PALETTES, "(pal)", NULL, NULL, NULL, 1, 0, 0, "", "kcf;pal;gpl"}, {FORMAT_ALL_PALETTES, "(pal)", NULL, NULL, NULL, 1, 0, 0, "", "kcf;pal;gpl"},
{FORMAT_ALL_FILES, "(*.*)", NULL, NULL, NULL, 0, 0, 0, "", "*"}, {FORMAT_ALL_FILES, "(*.*)", NULL, NULL, NULL, 0, 0, 0, "", "*"},
@ -156,6 +157,7 @@ const T_Format File_formats[] = {
#ifndef __no_tifflib__ #ifndef __no_tifflib__
{FORMAT_TIFF," tiff",Test_TIFF,Load_TIFF,Save_TIFF,0, 1, 1, "tif", "tif;tiff"}, {FORMAT_TIFF," tiff",Test_TIFF,Load_TIFF,Save_TIFF,0, 1, 1, "tif", "tif;tiff"},
#endif #endif
{FORMAT_GRB, " grb", Test_GRB, Load_GRB, NULL, 0, 0, 0, "grb", "grb;grob"},
{FORMAT_MISC,"misc.",NULL, NULL, NULL, 0, 0, 0, "", "tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff"}, {FORMAT_MISC,"misc.",NULL, NULL, NULL, 0, 0, 0, "", "tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff"},
}; };

View File

@ -2,7 +2,7 @@
*/ */
/* Grafx2 - The Ultimate 256-color bitmap paint program /* Grafx2 - The Ultimate 256-color bitmap paint program
Copyright 2018 Thomas Bernard Copyright 2018-2019 Thomas Bernard
Copyright 2011 Pawel Góralski Copyright 2011 Pawel Góralski
Copyright 2009 Petter Lindquist Copyright 2009 Petter Lindquist
Copyright 2008 Yves Rizoud Copyright 2008 Yves Rizoud
@ -2256,10 +2256,10 @@ NeoChrome Format :
Dali *.SD0 (ST low resolution) Dali *.SD0 (ST low resolution)
*.SD1 (ST medium resolution) *.SD1 (ST medium resolution)
*.SD2 (ST high resolution) *.SD2 (ST high resolution)
Files do not seem to have any resolution or bit plane info stored in them. The file Files do not seem to have any resolution or bit plane info stored in them. The file
extension seems to be the only way to determine the contents. extension seems to be the only way to determine the contents.
1 long file id? [always 0] 1 long file id? [always 0]
16 words palette 16 words palette
92 bytes reserved? [usually 0] 92 bytes reserved? [usually 0]
@ -2404,7 +2404,7 @@ void Load_NEO(T_IO_Context * context)
{ {
if (!Read_bytes(file, buffer, (resolution==2) ? 80 : 160)) if (!Read_bytes(file, buffer, (resolution==2) ? 80 : 160))
goto error; goto error;
ptr = buffer; ptr = buffer;
for (x_pos = 0; x_pos < width; ) for (x_pos = 0; x_pos < width; )
{ {
@ -7252,7 +7252,7 @@ void Save_HGR(T_IO_Context * context)
} }
if (context->Width == 560) if (context->Width == 560)
is_dhgr = 1; is_dhgr = 1;
file = Open_file_write(context); file = Open_file_write(context);
if (file == NULL) if (file == NULL)
return; return;
@ -7322,3 +7322,140 @@ void Save_HGR(T_IO_Context * context)
free(vram[1]); free(vram[1]);
fclose(file); fclose(file);
} }
///////////////////////////// HP-48 Grob Files ////////////////////////////
/**
* HP48 addresses are 20bits (5 nibbles)
* offset is in nibble (half byte)
*/
static dword Read_HP48Address(const byte * buffer, int offset)
{
dword data = 0;
int i = 4;
do
{
byte nibble;
nibble = buffer[(offset + i) >> 1];
if ((offset + i) & 1)
nibble >>= 4;
nibble &= 15;
data = (data << 4) | nibble;
}
while (i-- > 0);
return data;
}
/**
* Test for a HP-48 Grob file
*/
void Test_GRB(T_IO_Context * context, FILE * file)
{
byte buffer[18];
unsigned long file_size;
dword prologue, size, width, height;
(void)context;
File_error = 1;
file_size = File_length_file(file);
if (!Read_bytes(file, buffer, 18))
return;
if(memcmp(buffer, "HPHP48-R", 8) != 0)
return;
prologue = Read_HP48Address(buffer+8, 0);
size = Read_HP48Address(buffer+8, 5);
GFX2_Log(GFX2_DEBUG, "HP48 File detected. %lu bytes prologue %05x %u nibbles\n",
file_size, prologue, size);
if (prologue != 0x02b1e)
return;
height = Read_HP48Address(buffer+8, 10);
width = Read_HP48Address(buffer+8, 15);
GFX2_Log(GFX2_DEBUG, " Grob dimensions : %ux%u\n", width, height);
if ((file_size - 8) < ((size + 5) / 2))
return;
if (file_size < (18 + ((width + 7) >> 3) * height))
return;
File_error = 0;
}
void Load_GRB(T_IO_Context * context)
{
byte buffer[18];
byte * bitplane[4];
unsigned long file_size;
dword prologue, size, width, height;
byte bp, bpp;
FILE * file;
unsigned x, y;
File_error = 1;
file = Open_file_read(context);
if (file == NULL)
return;
file_size = File_length_file(file);
if (!Read_bytes(file, buffer, 18))
{
fclose(file);
return;
}
prologue = Read_HP48Address(buffer+8, 0);
size = Read_HP48Address(buffer+8, 5);
height = Read_HP48Address(buffer+8, 10);
width = Read_HP48Address(buffer+8, 15);
if (height >= 256)
bpp = 4;
else if (height >= 192)
bpp = 3;
else if (height >= 128)
bpp = 2;
else
bpp = 1;
File_error = 0;
Pre_load(context, width, height/bpp, file_size, FORMAT_GRB, PIXEL_SIMPLE, bpp);
if (File_error == 0)
{
dword bytes_per_plane = ((width + 7) >> 3) * (height/bpp);
dword offset = 0;
if (Config.Clear_palette)
memset(context->Palette, 0, sizeof(T_Palette));
for (x = 0; x < ((unsigned)1 << bpp); x++)
{
context->Palette[x].R = context->Palette[x].G = (x * 255) / ((1 << bpp) - 1);
context->Palette[x].B = 127;
}
// Load all bit planes
for (bp = 0; bp < bpp; bp++)
{
bitplane[bp] = GFX2_malloc(bytes_per_plane);
if (bitplane[bp])
{
if (!Read_bytes(file, bitplane[bp], bytes_per_plane))
File_error = 1;
}
}
// set pixels
for (y = 0; y < (height/bpp) && File_error == 0; y++)
{
for (x = 0; x < width; x++)
{
byte b = 0;
for (bp = 0; bp < bpp; bp++)
b |= ((bitplane[bp][offset] >> (x & 7)) & 1) << bp;
// invert because 1 is a black pixel on HP-48 LCD display
Set_pixel(context, x, y, b ^ ((1 << bpp) - 1));
if ((x & 7) == 7)
offset++;
}
if ((x & 7) != 7)
offset++;
}
// Free bit planes
for (bp = 0; bp < bpp; bp++)
free(bitplane[bp]);
}
fclose(file);
}