/* The Gimp plug-in for zx-ize pictures. (c) Juan-Antonio Fernández-Madrigal, 2011 Built up from the example blur plug-in by David Neary (http://developer.gimp.org/writing-a-plug-in/1/index.html) To install the plug-in in the ~/.gimp-2.x/plug-ins : Close The Gimp and write in console "gimptool-2.0 --install zxscreen.c" If there is any package missing (typically libgimp-dev), you will be warned at that call. */ #include /* --------------------- PROGRAM ROUTINES ------------------------ */ static void query(void); static void run(const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals); static void zx_ize(GimpDrawable *drawable); /* --------------------- PROGRAM CONSTANTS ------------------------ */ /* Number of pixels of a ZX attribute, both for width and height */ #define LENGTHATTR 8 /* Number of pixels of a ZX attribute */ #define AREAATTR ((LENGTHATTR)*(LENGTHATTR)) /* Number of ZX colors */ #define ZXNCOLORS 16 /* First ZX color index with bright */ #define FIRSTZXCOLORWITHBRIGHT 8 /* Level of channel for bright */ #define BRLEVEL 255 /* Level of channel for non-bright */ #define NLEVEL 192 /* For debugging (undefine if not) */ /* #define DEBUGGING */ /* --------------------- PROGRAM VARIABLES ------------------------ */ GimpPlugInInfo PLUG_IN_INFO={ NULL, NULL, query, run }; static guchar ZX_Colors[ZXNCOLORS][3]={ /* R,G,B for each ZX color (ZX order) */ {0,0,0}, /* Black */ {0,0,NLEVEL}, /* Blue */ {NLEVEL,0,0}, /* Red */ {NLEVEL,0,NLEVEL}, /* Magenta */ {0,NLEVEL,0}, /* Green */ {0,NLEVEL,NLEVEL}, /* Cyan */ {NLEVEL,NLEVEL,0}, /* Yellow */ {NLEVEL,NLEVEL,NLEVEL}, /* White */ {0,0,0}, /* -- From here on, the same */ {0,0,BRLEVEL}, /* colors, but with bright */ {BRLEVEL,0,0}, {BRLEVEL,0,BRLEVEL}, {0,BRLEVEL,0}, {0,BRLEVEL,BRLEVEL}, {BRLEVEL,BRLEVEL,0}, {BRLEVEL,BRLEVEL,BRLEVEL} }; /* --------------------- PROGRAM CODE ------------------------ */ MAIN() static void query(void) {static GimpParamDef args[]={ {GIMP_PDB_INT32,"run-mode","Run mode"}, {GIMP_PDB_IMAGE,"image","Input image"}, {GIMP_PDB_DRAWABLE,"drawable","Input drawable"} }; gimp_install_procedure("plug-in-zxscreen","ZX Screen", "Converts the image to the ZX Spectrum appearance", "Juan-Antonio Fernandez-Madrigal", "Copyright Juan-Antonio Fernandez-Madrigal", "2011","_ZX Screen","RGB*", GIMP_PLUGIN,G_N_ELEMENTS(args),0,args,NULL); gimp_plugin_menu_register("plug-in-zxscreen","/Filters/ZX"); } static void run(const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) {static GimpParam values[1]; GimpRunMode run_mode; GimpDrawable *drawable; /* Getting run_mode */ run_mode=param[0].data.d_int32; /* Get the specified drawable */ drawable=gimp_drawable_get(param[2].data.d_drawable); /* Do the work */ zx_ize(drawable); /* Setting mandatory output values */ *nreturn_vals=1; *return_vals=values; values[0].type=GIMP_PDB_STATUS; values[0].data.d_status=GIMP_PDB_SUCCESS; /* Dump the result back */ gimp_displays_flush(); gimp_drawable_detach(drawable); } static void zx_ize(GimpDrawable *drawable) {gint x1,y1,x2,y2,width,height,channels,xx,yy; GimpPixelRgn rgn_in,rgn_out; gint x0,y0,f,off,widthattrs,heightattrs,areaattrs,countattrs; guchar *bufferin,*bufferout; gint32 dists[ZXNCOLORS],auxgd,auxgd2,auxgd3; unsigned char ind,ind2; unsigned char zxcs[AREAATTR]; unsigned histo[ZXNCOLORS]; unsigned char zx_paper,zx_ink,notpaperink; /* Set status text */ gimp_progress_init("ZXScreen..."); /* Gets upper left and lower right coordinates, and layers number in the image */ gimp_drawable_mask_bounds(drawable->drawable_id,&x1,&y1,&x2,&y2); width=x2-x1; height=y2-y1; channels=gimp_drawable_bpp(drawable->drawable_id); if (channels<3) return; /* nothing to do when less than RGB information */ /* Allocate a big enough tile cache */ gimp_tile_cache_ntiles(2*(drawable->width/gimp_tile_width()+1)); /* Initialises two PixelRgns, one to read original data, * and the other to write output data. That second one will * be merged at the end by the call to * gimp_drawable_merge_shadow() */ gimp_pixel_rgn_init(&rgn_in,drawable,x1,y1,width,height,FALSE,FALSE); gimp_pixel_rgn_init(&rgn_out,drawable,x1,y1,width,height,TRUE,TRUE); /* Do the actual work */ widthattrs=width/LENGTHATTR; heightattrs=height/LENGTHATTR; areaattrs=widthattrs*heightattrs; countattrs=0; bufferin=g_new(guchar,AREAATTR*channels); bufferout=g_new(guchar,AREAATTR*channels); x0=x1; y0=y1; while (y0<=y2-LENGTHATTR) { /* Process each rectangle corresponding to a ZX attribute */ gimp_pixel_rgn_get_rect(&rgn_in,bufferin,x0,y0,LENGTHATTR,LENGTHATTR); /* Convert the colors of the pixels of that area to ZX colors */ for (f=0; fhisto[zx_ink]) zx_ink=ind; for (ind=0; ind0)) break; if (ind>=ZXNCOLORS) zx_paper=zx_ink; /* There is only one ZX color */ else /* There is more than one color in the area */ { zx_paper=0; if (zx_paper==zx_ink) zx_paper++; ind2=zx_paper+1; if (ind2==zx_ink) ind2++; for (ind=ind2; indhisto[zx_paper])) zx_paper=ind; } /* If both paper and ink have different brights, that must be fixed */ if (((zx_paper=FIRSTZXCOLORWITHBRIGHT))|| ((zx_paper>=FIRSTZXCOLORWITHBRIGHT)&&(zx_ink=FIRSTZXCOLORWITHBRIGHT) zx_paper+=FIRSTZXCOLORWITHBRIGHT; else zx_paper-=FIRSTZXCOLORWITHBRIGHT; } } /* Change the pixels of the area to only those in ink and those in paper: the ones that are not ink or paper are transformed into the closest one */ for (f=0; f3) bufferout[off+3]=255; } #ifdef DEBUGGING xx=0; yy=0; for (f=0; f3) bufferout[off+3]=255; xx++; if (xx>=LENGTHATTR) { xx=0; yy++; } } #endif /* Dump the resulting colors to the image */ gimp_pixel_rgn_set_rect(&rgn_out,bufferout,x0,y0,LENGTHATTR,LENGTHATTR); /* Prepare area of the image corresponding to the next ZX attr */ x0+=LENGTHATTR; if (x0>x2-LENGTHATTR) { x0=x1; y0+=LENGTHATTR; } countattrs++; gimp_progress_update((gdouble)countattrs/(gdouble)areaattrs); } g_free(bufferout); g_free(bufferin); /* Update the modified region */ gimp_progress_end(); gimp_drawable_flush(drawable); gimp_drawable_merge_shadow(drawable->drawable_id,TRUE); gimp_drawable_update(drawable->drawable_id,x1,y1,width,height); }