rawphoto.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /*
  2. Raw photo loader plugin for The GIMP
  3. by Dave Coffin at cybercom dot net, user dcoffin
  4. http://www.cybercom.net/~dcoffin/
  5. $Revision: 1.32 $
  6. $Date: 2008/09/16 05:41:39 $
  7. This code is licensed under the same terms as The GIMP.
  8. To simplify maintenance, it calls my command-line "dcraw"
  9. program to do the actual decoding.
  10. To install locally:
  11. gimptool --install rawphoto.c
  12. To install globally:
  13. gimptool --install-admin rawphoto.c
  14. To build without installing:
  15. gcc -o rawphoto rawphoto.c `gtk-config --cflags --libs` -lgimp -lgimpui
  16. */
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <gtk/gtk.h>
  21. #include <libgimp/gimp.h>
  22. #include <libgimp/gimpui.h>
  23. #if GIMP_CHECK_VERSION(1,3,2)
  24. #define GimpRunModeType GimpRunMode
  25. #endif
  26. #if GIMP_CHECK_VERSION(1,3,17)
  27. #define RAWPHOTO_CONST const
  28. #else
  29. #define RAWPHOTO_CONST
  30. #endif
  31. #include <locale.h>
  32. #include <libintl.h>
  33. #define _(String) gettext(String)
  34. #define PLUG_IN_VERSION "1.1.20 - 16 September 2008"
  35. static void query(void);
  36. static void run(RAWPHOTO_CONST gchar *name,
  37. gint nparams,
  38. RAWPHOTO_CONST GimpParam *param,
  39. gint *nreturn_vals,
  40. GimpParam **return_vals);
  41. static gint load_dialog (gchar *name);
  42. static gint32 load_image (gchar *filename);
  43. GimpPlugInInfo PLUG_IN_INFO =
  44. {
  45. NULL, /* init_procedure */
  46. NULL, /* quit_procedure */
  47. query, /* query_procedure */
  48. run, /* run_procedure */
  49. };
  50. static struct {
  51. gboolean check_val[6];
  52. gfloat spin_val[2];
  53. } cfg = {
  54. { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE },
  55. { 1, 0 }
  56. };
  57. MAIN ()
  58. static void query (void)
  59. {
  60. static GimpParamDef load_args[] =
  61. {
  62. { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  63. { GIMP_PDB_STRING, "filename", "The name of the file to load" },
  64. { GIMP_PDB_STRING, "raw_filename", "The name of the file to load" },
  65. };
  66. static GimpParamDef load_return_vals[] =
  67. {
  68. { GIMP_PDB_IMAGE, "image", "Output image" },
  69. };
  70. static gint num_load_args =
  71. sizeof load_args / sizeof load_args[0];
  72. static gint num_load_return_vals =
  73. sizeof load_return_vals / sizeof load_return_vals[0];
  74. gimp_install_procedure ("file_rawphoto_load",
  75. "Loads raw digital camera files",
  76. "This plug-in loads raw digital camera files.",
  77. "Dave Coffin at cybercom dot net, user dcoffin",
  78. "Copyright 2003-2008 by Dave Coffin",
  79. PLUG_IN_VERSION,
  80. "<Load>/rawphoto",
  81. NULL,
  82. GIMP_PLUGIN,
  83. num_load_args,
  84. num_load_return_vals,
  85. load_args,
  86. load_return_vals);
  87. gimp_register_load_handler ("file_rawphoto_load",
  88. "3fr,arw,bay,bmq,cine,cr2,crw,cs1,dc2,dcr,dng,erf,fff,hdr,ia,jpg,k25,kc2,kdc,mdc,mef,mos,mrw,nef,nrw,orf,pef,pxn,qtk,raf,raw,rdc,rw2,sr2,srf,sti,tif,x3f", "");
  89. }
  90. static void run (RAWPHOTO_CONST gchar *name,
  91. gint nparams,
  92. RAWPHOTO_CONST GimpParam *param,
  93. gint *nreturn_vals,
  94. GimpParam **return_vals)
  95. {
  96. static GimpParam values[2];
  97. GimpRunModeType run_mode;
  98. GimpPDBStatusType status;
  99. gint32 image_id = -1;
  100. gchar *command, *fname;
  101. int stat;
  102. *nreturn_vals = 1;
  103. *return_vals = values;
  104. status = GIMP_PDB_CALLING_ERROR;
  105. if (strcmp (name, "file_rawphoto_load")) goto done;
  106. status = GIMP_PDB_EXECUTION_ERROR;
  107. fname = param[1].data.d_string;
  108. command = g_malloc (strlen(fname)+20);
  109. if (!command) goto done;
  110. /*
  111. Is the file really a raw photo? If not, try loading it
  112. as a regular JPEG or TIFF.
  113. */
  114. sprintf (command, "dcraw -i '%s'\n",fname);
  115. fputs (command, stderr);
  116. stat = system (command);
  117. g_free (command);
  118. if (stat) {
  119. if (stat > 0x200)
  120. g_message (_("The \"rawphoto\" plugin won't work because "
  121. "there is no \"dcraw\" executable in your path."));
  122. if (!strcasecmp (fname + strlen(fname) - 4, ".jpg"))
  123. *return_vals = gimp_run_procedure2
  124. ("file_jpeg_load", nreturn_vals, nparams, param);
  125. else
  126. *return_vals = gimp_run_procedure2
  127. ("file_tiff_load", nreturn_vals, nparams, param);
  128. return;
  129. }
  130. gimp_get_data ("plug_in_rawphoto", &cfg);
  131. status = GIMP_PDB_CANCEL;
  132. run_mode = param[0].data.d_int32;
  133. if (run_mode == GIMP_RUN_INTERACTIVE)
  134. if (!load_dialog (param[1].data.d_string)) goto done;
  135. status = GIMP_PDB_EXECUTION_ERROR;
  136. image_id = load_image (param[1].data.d_string);
  137. if (image_id == -1) goto done;
  138. *nreturn_vals = 2;
  139. values[1].type = GIMP_PDB_IMAGE;
  140. values[1].data.d_image = image_id;
  141. status = GIMP_PDB_SUCCESS;
  142. gimp_set_data ("plug_in_rawphoto", &cfg, sizeof cfg);
  143. done:
  144. values[0].type = GIMP_PDB_STATUS;
  145. values[0].data.d_status = status;
  146. }
  147. static gint32 load_image (gchar *filename)
  148. {
  149. int tile_height, depth, width, height, row, nrows;
  150. FILE *pfp;
  151. gint32 image, layer;
  152. GimpDrawable *drawable;
  153. GimpPixelRgn pixel_region;
  154. guchar *pixel;
  155. char *command, nl;
  156. setlocale (LC_NUMERIC, "C");
  157. command = g_malloc (strlen(filename)+100);
  158. if (!command) return -1;
  159. sprintf (command,
  160. "dcraw -c%s%s%s%s%s%s -b %0.2f -H %d '%s'\n",
  161. cfg.check_val[0] ? " -q 0":"",
  162. cfg.check_val[1] ? " -h":"",
  163. cfg.check_val[2] ? " -f":"",
  164. cfg.check_val[3] ? " -d":"",
  165. cfg.check_val[4] ? " -a":"",
  166. cfg.check_val[5] ? " -w":"",
  167. cfg.spin_val[0], (int) cfg.spin_val[1],
  168. filename );
  169. fputs (command, stderr);
  170. pfp = popen (command, "r");
  171. g_free (command);
  172. if (!pfp) {
  173. perror ("dcraw");
  174. return -1;
  175. }
  176. if (fscanf (pfp, "P%d %d %d 255%c", &depth, &width, &height, &nl) != 4
  177. || (depth-5)/2 ) {
  178. pclose (pfp);
  179. g_message ("Not a raw digital camera image.\n");
  180. return -1;
  181. }
  182. depth = depth*2 - 9;
  183. image = gimp_image_new (width, height, depth == 3 ? GIMP_RGB : GIMP_GRAY);
  184. if (image == -1) {
  185. pclose (pfp);
  186. g_message ("Can't allocate new image.\n");
  187. return -1;
  188. }
  189. gimp_image_set_filename (image, filename);
  190. /* Create the "background" layer to hold the image... */
  191. layer = gimp_layer_new (image, "Background", width, height,
  192. depth == 3 ? GIMP_RGB_IMAGE : GIMP_GRAY_IMAGE,
  193. 100, GIMP_NORMAL_MODE);
  194. gimp_image_add_layer (image, layer, 0);
  195. /* Get the drawable and set the pixel region for our load... */
  196. drawable = gimp_drawable_get (layer);
  197. gimp_pixel_rgn_init (&pixel_region, drawable, 0, 0, drawable->width,
  198. drawable->height, TRUE, FALSE);
  199. /* Temporary buffers... */
  200. tile_height = gimp_tile_height();
  201. pixel = g_new (guchar, tile_height * width * depth);
  202. /* Load the image... */
  203. for (row = 0; row < height; row += tile_height) {
  204. nrows = height - row;
  205. if (nrows > tile_height)
  206. nrows = tile_height;
  207. fread (pixel, width * depth, nrows, pfp);
  208. gimp_pixel_rgn_set_rect (&pixel_region, pixel, 0, row, width, nrows);
  209. }
  210. pclose (pfp);
  211. g_free (pixel);
  212. gimp_drawable_flush (drawable);
  213. gimp_drawable_detach (drawable);
  214. return image;
  215. }
  216. #if !GIMP_CHECK_VERSION(1,3,23)
  217. /* this is set to true after OK click in any dialog */
  218. gboolean result = FALSE;
  219. static void callback_ok (GtkWidget * widget, gpointer data)
  220. {
  221. result = TRUE;
  222. gtk_widget_destroy (GTK_WIDGET (data));
  223. }
  224. #endif
  225. #define NCHECK (sizeof cfg.check_val / sizeof (gboolean))
  226. gint load_dialog (gchar * name)
  227. {
  228. GtkWidget *dialog;
  229. GtkWidget *table;
  230. GtkObject *adj;
  231. GtkWidget *widget;
  232. int i;
  233. static const char *label[9] =
  234. { "Quick interpolation", "Half-size interpolation",
  235. "Four color interpolation", "Grayscale document",
  236. "Automatic white balance", "Camera white balance",
  237. "Brightness", "Highlight mode" };
  238. gimp_ui_init ("rawphoto", TRUE);
  239. dialog = gimp_dialog_new (_("Raw Photo Loader " PLUG_IN_VERSION), "rawphoto",
  240. #if !GIMP_CHECK_VERSION(1,3,23)
  241. gimp_standard_help_func, "rawphoto",
  242. GTK_WIN_POS_MOUSE,
  243. FALSE, TRUE, FALSE,
  244. _("OK"), callback_ok, NULL, NULL, NULL, TRUE,
  245. FALSE, _("Cancel"), gtk_widget_destroy, NULL,
  246. 1, NULL, FALSE, TRUE, NULL);
  247. gtk_signal_connect
  248. (GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
  249. #else
  250. NULL, 0,
  251. gimp_standard_help_func, "rawphoto",
  252. GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
  253. GTK_STOCK_OK, GTK_RESPONSE_OK,
  254. NULL);
  255. #endif
  256. table = gtk_table_new (9, 2, FALSE);
  257. gtk_container_set_border_width (GTK_CONTAINER(table), 6);
  258. gtk_box_pack_start
  259. (GTK_BOX(GTK_DIALOG(dialog)->vbox), table, FALSE, FALSE, 0);
  260. gtk_widget_show (table);
  261. for (i=0; i < NCHECK; i++) {
  262. widget = gtk_check_button_new_with_label
  263. (_(label[i]));
  264. gtk_toggle_button_set_active
  265. (GTK_TOGGLE_BUTTON (widget), cfg.check_val[i]);
  266. gtk_table_attach
  267. (GTK_TABLE(table), widget, 0, 2, i, i+1, GTK_FILL, GTK_FILL, 0, 0);
  268. gtk_signal_connect (GTK_OBJECT (widget), "toggled",
  269. GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  270. &cfg.check_val[i]);
  271. gtk_widget_show (widget);
  272. }
  273. for (i=NCHECK; i < NCHECK+2; i++) {
  274. widget = gtk_label_new (_(label[i]));
  275. gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
  276. gtk_misc_set_padding (GTK_MISC (widget), 10, 0);
  277. gtk_table_attach
  278. (GTK_TABLE(table), widget, 0, 1, i, i+1, GTK_FILL, GTK_FILL, 0, 0);
  279. gtk_widget_show (widget);
  280. if (i == NCHECK+1)
  281. widget = gimp_spin_button_new
  282. (&adj, cfg.spin_val[i-NCHECK], 0, 9, 1, 9, 1, 1, 0);
  283. else
  284. widget = gimp_spin_button_new
  285. (&adj, cfg.spin_val[i-NCHECK], 0.01, 4.0, 0.01, 0.1, 0.1, 0.1, 2);
  286. gtk_table_attach
  287. (GTK_TABLE(table), widget, 1, 2, i, i+1, GTK_FILL, GTK_FILL, 0, 0);
  288. gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  289. GTK_SIGNAL_FUNC (gimp_float_adjustment_update),
  290. &cfg.spin_val[i-NCHECK]);
  291. gtk_widget_show (widget);
  292. }
  293. gtk_widget_show (dialog);
  294. #if !GIMP_CHECK_VERSION(1,3,23)
  295. gtk_main();
  296. gdk_flush();
  297. return result;
  298. #else
  299. i = gimp_dialog_run (GIMP_DIALOG (dialog));
  300. gtk_widget_destroy (dialog);
  301. return i == GTK_RESPONSE_OK;
  302. #endif
  303. }