/* * This is a plugin for the GIMP. * This plugin can load Neochrome images (file format used on Atari ST). * * Copyright (C) 1999 Alain Gaymard * Original source for Degas images by Markus Franz Xaver Johannes Oberhumer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Alain Gaymard * * http://perso.club-internet.fr/agaymard */ /* * Version Information: * * 0.10 11-MAR-1999 loads NEO * 0.20 05-AUG-1999 check image size (320x200), remove unused function readc * * Note: set tabsize to 4 */ #include #include #include #include #include /*********************************************************************** // ************************************************************************/ typedef struct Pic Pic; struct Pic { int fd; int read_error; int width; int height; int planes; int colors; int bpl; /* bytes per line */ guchar cmap[16 * 3]; int (*read_pic) (Pic *h, guchar *buf); }; /*********************************************************************** // util ************************************************************************/ static int read_line(Pic *h, int y, guchar *line) { if ((y % 16) == 0) gimp_progress_update((double) y / (double) h->height); if (read(h->fd, line, h->bpl) == h->bpl) return 0; h->read_error = 1; return -1; } /*********************************************************************** // NEO - 320x200x16 ************************************************************************/ static int read_neo(Pic *h, guchar *buf) { int x, y, c; guchar line[160], *l; for (y = 0; y < h->height; y++, buf += h->width) { if (read_line(h, y, line) != 0) return -1; /* for each 16 pixel block */ for (x = 0, l = line; x < h->width; l += 8) { unsigned p0 = (l[0] << 8) | l[1]; unsigned p1 = (l[2] << 8) | l[3]; unsigned p2 = (l[4] << 8) | l[5]; unsigned p3 = (l[6] << 8) | l[7]; /* decode planes */ for (c = 0; c < 16; c++) { buf[x++] = ((p0 >> 15) & 1) | ((p1 >> 14) & 2) | ((p2 >> 13) & 4) | ((p3 >> 12) & 8); p0 <<= 1; p1 <<= 1; p2 <<= 1; p3 <<= 1; } } } return h->read_error ? -1 : 0; } /*********************************************************************** // ************************************************************************/ static int read_header(Pic *h) { guchar head[4]; guchar pal[16 * 2]; guchar fill[92]; int i, j; if (read(h->fd, head, 4) != 4 || read(h->fd, pal, 16 * 2) != 16 * 2 || read(h->fd, fill, 92) != 92 ) { h->read_error = 1; return -1; } /* check the image size. Always 320x200 */ if ((0 != fill[18]*256 + fill[19]) || (0 != fill[20]*256 + fill[21]) || (320 != fill[22]*256 + fill[23]) || (200 != fill[24]*256 + fill[25])) { fprintf(stderr, "neochrome: read_header failed! Wrong image size.\n"); h->read_error = 1; return -1; } h->width = 320; h->height = 200; h->planes = 4; h->read_pic = read_neo; h->colors = 1 << h->planes; h->bpl = (h->width * h->planes) / 8; /* convert pal: 0..7 -> 0..255 */ for (i = j = 0; i < h->colors; i++) { static const guchar tab[8] = { 0, 36, 73, 109, 146, 182, 219, 255 }; unsigned col = (pal[2 * i] << 8) | pal[2 * i + 1]; h->cmap[j++] = tab[(col >> 8) & 7]; h->cmap[j++] = tab[(col >> 4) & 7]; h->cmap[j++] = tab[(col >> 0) & 7]; } return 0; } /*********************************************************************** // ************************************************************************/ static gint32 load_neochrome(char *filename) { gint32 image_ID; gint32 layer_ID; GimpPixelRgn pixel_rgn; GimpDrawable *drawable; char *name; guchar *buf; Pic pic; Pic *h; int r; h = &pic; h->read_error = 0; name = g_new(char, strlen(filename) + 12); if (name == 0) { fprintf(stderr, "neochrome: unable to allocate memory!\n"); gimp_quit(); } sprintf(name, "Loading %s:", filename); gimp_progress_init(name); g_free(name); h->fd = open(filename, O_RDONLY); if (h->fd < 0) { fprintf(stderr, "neochrome: unable to open file %s\n", filename); gimp_quit(); } if (read_header(h) != 0) { close(h->fd); fprintf(stderr, "neochrome: read_header failed!\n"); gimp_quit(); } image_ID = gimp_image_new(h->width, h->height, GIMP_INDEXED); gimp_image_set_filename(image_ID, filename); gimp_image_set_cmap(image_ID, h->cmap, h->colors); layer_ID = gimp_layer_new(image_ID, "Background", h->width, h->height, GIMP_INDEXED_IMAGE, 100, GIMP_NORMAL_MODE); gimp_image_add_layer(image_ID, layer_ID, 0); drawable = gimp_drawable_get(layer_ID); gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE); buf = g_new(guchar, h->width * h->height); if (buf == 0) { fprintf(stderr, "neochrome: unable to allocate memory!\n"); gimp_quit(); } r = (*h->read_pic) (h, buf); close(h->fd); if (r != 0) { g_free(buf); fprintf(stderr, "neochrome: read_pic failed!\n"); gimp_quit(); } gimp_pixel_rgn_set_rect(&pixel_rgn, buf, 0, 0, h->width, h->height); gimp_progress_update(1.0); g_free(buf); gimp_drawable_flush(drawable); return image_ID; } /*********************************************************************** // run ************************************************************************/ static void run(char *name, int nparams, GimpParam *param, int *nreturn_vals, GimpParam **return_vals) { static GimpParam values[2]; GimpRunModeType run_mode; gint32 image_ID; *nreturn_vals = 1; *return_vals = values; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = GIMP_PDB_CALLING_ERROR; if (nparams < 2) return; run_mode = param[0].data.d_int32; if (strcmp(name, "file_neochrome_load") == 0) { values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; image_ID = load_neochrome(param[1].data.d_string); if (image_ID != -1) { *nreturn_vals = 2; values[0].data.d_status = GIMP_PDB_SUCCESS; values[1].type = GIMP_PDB_IMAGE; values[1].data.d_image = image_ID; } } } /*********************************************************************** // ************************************************************************/ static void query(void) { static GimpParamDef load_args[] = { {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"}, {GIMP_PDB_STRING, "filename", "The name of the file to load"}, {GIMP_PDB_STRING, "raw_filename", "The name of the file to load"}, }; static GimpParamDef load_return_vals[] = { {GIMP_PDB_IMAGE, "image", "Output image"}, }; static int nload_args = sizeof(load_args) / sizeof(load_args[0]); static int nload_return_vals = sizeof(load_return_vals) / sizeof(load_return_vals[0]); gimp_install_procedure("file_neochrome_load", "loads images of the Neochrome file format", "This plug-in loads images of the Neochrome file format.", "Alain Gaymard", "Alain Gaymard", "1999", "/Neochrome", NULL, GIMP_PLUGIN, nload_args, nload_return_vals, load_args, load_return_vals); #if 1 gimp_register_load_handler("file_neochrome_load", "neo", ""); #else /* signature of Neochrome images is way too short */ gimp_register_magic_load_handler("file_neochrome_load", "neo", "", "0,short,0x8000,0,short,0x0000,short,0x8001,0,short,0x0001,short,0x8002,0,short,0x0002"); #endif } /*********************************************************************** // ************************************************************************/ GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; MAIN(); /* vi:ts=4 */