/* * 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. */ /* * PhotoCD loading file filter for the GIMP * (c) 1996 Gerd Knorr * * Converted to new style gtk GIMP plug-in * 1997 Larry Ewing * * It loads the image with one of the reolutions 192x128, 384x256 * and 768x512 as RGB_IMAGE * * Some of the code is just cut-and pasted from the JPEG plug-in * (from Peter Mattis) * * Some of the code from gbr.c by Tim Newsome * * */ #include #include #include #include #include #include "gtk/gtk.h" #include "libgimp/gimp.h" /*--------------------------------------------------------*/ static char *prog_name; /*--------------------------------------------------------*/ static int gray_LUT[256] = { 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 14, 15, 16, 18, 19, 21, 22, 24, 25, 26, 28, 29, 31, 32, 33, 35, 36, 38, 39, 41, 42, 43, 45, 46, 48, 49, 50, 52, 53, 55, 56, 57, 59, 60, 62, 63, 65, 66, 67, 69, 70, 72, 73, 74, 76, 77, 79, 80, 82, 83, 84, 86, 87, 89, 90, 91, 93, 94, 96, 97, 99, 100, 101, 103, 104, 106, 107, 108, 110, 111, 113, 114, 115, 117, 118, 120, 121, 123, 124, 125, 127, 128, 130, 131, 132, 134, 135, 137, 138, 140, 141, 142, 144, 145, 147, 148, 149, 151, 152, 154, 155, 156, 158, 159, 161, 162, 164, 165, 166, 168, 169, 171, 172, 173, 175, 176, 178, 179, 181, 182, 183, 185, 186, 188, 189, 190, 192, 193, 195, 196, 198, 199, 200, 202, 203, 205, 206, 207, 209, 210, 212, 213, 214, 216, 217, 219, 220, 222, 223, 224, 226, 227, 229, 230, 231, 233, 234, 236, 237, 239, 240, 241, 243, 244, 246, 247, 248, 250, 251, 253, 254, 256, 257, 258, 260, 261, 263, 264, 265, 267, 268, 270, 271, 272, 274, 275, 277, 278, 280, 281, 282, 284, 285, 287, 288, 289, 291, 292, 294, 295, 297, 298, 299, 301, 302, 304, 305, 306, 308, 309, 311, 312, 313, 315, 316, 318, 319, 321, 322, 323, 325, 326, 328, 329, 330, 332, 333, 335, 336, 338, 339, 340, 342, 343, 345, 346, 347, 349, 350, 352, 353, 355, 356, 357, 359, 360 }; static int blue_LUT[256] = { -318, -316, -314, -312, -310, -308, -306, -304, -302, -300, -298, -296, -294, -292, -290, -288, -286, -284, -282, -280, -278, -276, -274, -272, -270, -268, -266, -264, -262, -260, -258, -256, -254, -252, -250, -248, -246, -244, -242, -240, -238, -236, -234, -232, -230, -228, -226, -224, -222, -220, -218, -216, -214, -212, -210, -208, -206, -204, -202, -200, -198, -196, -194, -192, -190, -188, -186, -184, -182, -180, -178, -176, -174, -172, -170, -168, -166, -164, -162, -160, -158, -156, -154, -152, -150, -148, -146, -144, -142, -140, -138, -136, -134, -132, -130, -128, -126, -124, -122, -120, -118, -116, -114, -112, -110, -108, -106, -104, -102, -100, -98, -96, -94, -92, -90, -88, -86, -84, -82, -80, -78, -76, -74, -72, -70, -68, -66, -64, -62, -60, -58, -56, -54, -52, -50, -48, -46, -44, -42, -40, -38, -36, -34, -32, -30, -28, -26, -24, -22, -20, -18, -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, }; static int red_LUT[256] = { -274, -272, -270, -268, -266, -264, -262, -260, -258, -256, -254, -252, -250, -248, -246, -244, -242, -240, -238, -236, -234, -232, -230, -228, -226, -224, -222, -220, -218, -216, -214, -212, -210, -208, -206, -204, -202, -200, -198, -196, -194, -192, -190, -188, -186, -184, -182, -180, -178, -176, -174, -172, -170, -168, -166, -164, -162, -160, -158, -156, -154, -152, -150, -148, -146, -144, -142, -140, -138, -136, -134, -132, -130, -128, -126, -124, -122, -120, -118, -116, -114, -112, -110, -108, -106, -104, -102, -100, -98, -96, -94, -92, -90, -88, -86, -84, -82, -80, -78, -76, -74, -72, -70, -68, -66, -64, -62, -60, -58, -56, -54, -52, -50, -48, -46, -44, -42, -40, -38, -36, -34, -32, -30, -28, -26, -24, -22, -20, -18, -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, }; int run_flag = 0; static void query (void); static void run (char *name, int nparams, GParam *param, int *nreturn_vals, GParam **return_vals); static gint32 load_image (char *filename); static void close_callback(GtkWidget * widget, gpointer data); static void ok_callback(GtkWidget * widget, gpointer data); static void entry_callback(GtkWidget * widget, gpointer data); static int size_dialog(void); /* Untouched --------------------------------------------------------*/ GPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; typedef struct { int size; int rotate; } pcd_info; enum sizes { SIZE_192x128, SIZE_348x256, SIZE_768x512, NUM_SIZES }; char *size_strings[NUM_SIZES] = { "192x128", "348x256", "768x512" }; pcd_info info = { SIZE_768x512, 0 }; MAIN (); static void query () { static GParamDef load_args[] = { { PARAM_INT32, "run_mode", "Interactive, non-interactive" }, { PARAM_STRING, "filename", "The name of the file to load" }, { PARAM_STRING, "raw_filename", "The name of the file to load" }, }; static GParamDef load_return_vals[] = { { PARAM_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_pcd_load", "loads files of the .pcd file format", "FIXME: write help", "Gerd Knorr, Larry Ewing", "Gerd Knorr, Larry Ewing", "1997", "/PhotoCD", NULL, PROC_PLUG_IN, nload_args, nload_return_vals, load_args, load_return_vals); gimp_register_load_handler ("file_pcd_load", "pcd,PCD", ""); } /*--------------------------------------------------------*/ static void run (char *name, int nparams, GParam *param, int *nreturn_vals, GParam **return_vals) { static GParam values[2]; GRunModeType run_mode; gint32 image_ID; run_mode = param[0].data.d_int32; *nreturn_vals = 2; *return_vals = values; values[0].type = PARAM_STATUS; values[0].data.d_status = STATUS_CALLING_ERROR; values[1].type = PARAM_IMAGE; values[1].data.d_image = -1; if (strcmp (name, "file_pcd_load") == 0) { gimp_get_data ("file_pcd_load", &info); switch (run_mode) { case RUN_INTERACTIVE: if(!size_dialog()) return; break; case RUN_NONINTERACTIVE: case RUN_WITH_LAST_VALS: break; } image_ID = load_image (param[1].data.d_string); if (image_ID != -1) { values[0].data.d_status = STATUS_SUCCESS; values[1].data.d_image = image_ID; gimp_set_data ("file_pcd_load", &info, sizeof(info)); } else { values[0].data.d_status = STATUS_EXECUTION_ERROR; } } } int size_dialog () { GtkWidget *dlg; GtkWidget *box1; GtkWidget *box2; GtkWidget *button; GtkWidget *label; GtkWidget *separator; gchar **argv; gint argc; int i; argc = 1; argv = g_new(gchar *, 1); argv[0] = g_strdup("PhotoCD"); gtk_init(&argc, &argv); /* set the size because we have a dialog */ dlg = gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dlg), "Image Size"); gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE); gtk_signal_connect(GTK_OBJECT(dlg), "destroy", (GtkSignalFunc) close_callback, NULL); /* Action area */ button = gtk_button_new_with_label("OK"); GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) ok_callback, dlg); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0); gtk_widget_grab_default(button); gtk_widget_show(button); button = gtk_button_new_with_label("Cancel"); GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_signal_connect_object(GTK_OBJECT(button), "clicked", (GtkSignalFunc) gtk_widget_destroy, GTK_OBJECT(dlg)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0); gtk_widget_show(button); /* the choices */ box1 = GTK_DIALOG(dlg)->vbox; box2 = gtk_vbox_new (FALSE, 10); gtk_container_border_width (GTK_CONTAINER (box2), 10); gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); gtk_widget_show (box2); label = gtk_label_new ("Choose an image size"); gtk_box_pack_start (GTK_BOX (box2), label, TRUE, TRUE, 0); gtk_widget_show (label); separator = gtk_hseparator_new (); gtk_box_pack_start (GTK_BOX (box2), separator, TRUE, TRUE, 0); gtk_widget_show (separator); for (i = 0; i < NUM_SIZES; i++) { if (i == 0) button = gtk_radio_button_new_with_label (NULL, size_strings[i]); else button = gtk_radio_button_new_with_label (gtk_radio_button_group (GTK_RADIO_BUTTON (button)), size_strings[i]); gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) entry_callback, (gpointer)i); gtk_widget_show (button); /* Set the toggle button to the current size */ if (i == info.size) gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE); } gtk_widget_show(dlg); gtk_main(); gdk_flush(); return run_flag; } static gint32 load_image(char *filename) { FILE *fp; int x,y,i,r,b,g,gray,width,height,seek; char *temp; gint32 image_ID, layer_ID; GDrawable *drawable; GPixelRgn pixel_rgn; gchar *buffer; unsigned char gray1[768]; unsigned char gray2[768]; unsigned char red[384]; unsigned char blue[384]; switch (info.size) { case SIZE_192x128: width = 192; height = 128; seek = 8192; break; case SIZE_348x256: width = 384; height = 256; seek = 47104; break; case SIZE_768x512: width = 768; height = 512; seek = 196608; break; case -1: default: return -1; } temp = g_malloc (strlen (filename) + 11); sprintf (temp, "Loading %s:", filename); gimp_progress_init (temp); g_free (temp); if ((fp = fopen (filename, "rb")) == NULL) { printf ("%s: can't open \"%s\"\n", prog_name, filename); return -1; } fseek(fp,seek,SEEK_SET); image_ID = gimp_image_new (width,height, RGB_IMAGE); gimp_image_set_filename(image_ID, filename); layer_ID = gimp_layer_new(image_ID, "Background", width, height, RGB_IMAGE, 100, 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); buffer = g_malloc(width * 3 * sizeof(gint)); for (y = 0; y < height; y += 2) { fread(gray1,width,1,fp); fread(gray2,width,1,fp); fread(blue,width/2,1,fp); if( 1 != fread(red,width/2,1,fp)) { g_free(buffer); fclose(fp); return -1; } for (x = 0, i = 0; x < width; x++) { gray = gray_LUT[gray1[x]]; b = gray + blue_LUT[blue[x >> 1]]; r = gray + red_LUT [red [x >> 1]]; g = (10*gray - b - 3*r) / 6; buffer[i++] = (r & ~0xff) ? ((r < 0) ? 0 : 255 ) : r; buffer[i++] = (g & ~0xff) ? ((g < 0) ? 0 : 255 ) : g; buffer[i++] = (b & ~0xff) ? ((b < 0) ? 0 : 255 ) : b; } gimp_pixel_rgn_set_row(&pixel_rgn, buffer, 0, y, width); gimp_progress_update ((double)y/(double)height); for (x = 0, i = 0; x < width; x++) { gray = gray_LUT[gray2[x]]; b = gray + blue_LUT[blue[x >> 1]]; r = gray + red_LUT [red [x >> 1]]; g = (10*gray - b - 3*r) / 6; buffer[i++] = (r & ~0xff) ? ((r < 0) ? 0 : 255 ) : r; buffer[i++] = (g & ~0xff) ? ((g < 0) ? 0 : 255 ) : g; buffer[i++] = (b & ~0xff) ? ((b < 0) ? 0 : 255 ) : b; } gimp_pixel_rgn_set_row(&pixel_rgn, buffer, 0, y+1, width); gimp_progress_update ((double)(y + 1)/(double)height); } gimp_drawable_flush(drawable); g_free(buffer); fclose(fp); return image_ID; } static void close_callback(GtkWidget * widget, gpointer data) { gtk_main_quit(); } static void ok_callback(GtkWidget * widget, gpointer data) { run_flag = 1; gtk_widget_destroy(GTK_WIDGET(data)); } static void entry_callback(GtkWidget * widget, gpointer data) { info.size = (int)data; }