1 /*
2 *
3 *
4 Copyright 2010-2011 Sebastian Kraft
5
6 This file is part of GimpLensfun.
7
8 GimpLensfun is free software: you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation, either version
11 3 of the License, or (at your option) any later version.
12
13 GimpLensfun is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied
15 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 PURPOSE. See the GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public
19 License along with GimpLensfun. If not, see
20 http://www.gnu.org/licenses/.
21
22 */
23
24 #include <stdio.h>
25 #include <math.h>
26 #include <string>
27 #include <vector>
28 #include <float.h>
29
30 #include <lensfun/lensfun.h>
31 #include <libgimp/gimp.h>
32 #include <libgimp/gimpui.h>
33
34 #include <exiv2/error.hpp>
35 #include <exiv2/image.hpp>
36 #include <exiv2/exif.hpp>
37
38 #define VERSIONSTR "0.2.5-dev"
39
40
41 #ifndef DEBUG
42 #define DEBUG 0
43 #endif
44
45 #include "LUT.hpp"
46
47 using namespace std;
48
49 //####################################################################
50 // Function declarations
51 static void query (void);
52 static void run (const gchar *name,
53 gint nparams,
54 const GimpParam *param,
55 gint *nreturn_vals,
56 GimpParam **return_vals);
57
58 static gboolean create_dialog_window (GimpDrawable *drawable);
59 //--------------------------------------------------------------------
60
61
62 //####################################################################
63 // Global variables
64 GtkWidget *camera_combo, *maker_combo, *lens_combo;
65 GtkWidget *CorrVignetting, *CorrTCA, *CorrDistortion;
66 lfDatabase *ldb;
67 bool bComboBoxLock = false;
68 //--------------------------------------------------------------------
69
70
71 //####################################################################
72 // interpolation parameters
73 const int cLanczosWidth = 2;
74 const int cLanczosTableRes = 256;
75 LUT<float> LanczosLUT (cLanczosWidth * 2 * cLanczosTableRes + 1);
76
77 typedef enum GL_INTERPOL {
78 GL_INTERPOL_NN, // Nearest Neighbour
79 GL_INTERPOL_BL, // Bilinear
80 GL_INTERPOL_LZ // Lanczos
81 } glInterpolationType;
82
83
84 //####################################################################
85 // List of camera makers
86 const string CameraMakers[] = {
87 "Canon",
88 "Casio",
89 "Fujifilm",
90 "GoPro",
91 "Kodak",
92 "Konica",
93 "Leica",
94 "Nikon",
95 "Olympus",
96 "Panasonic",
97 "Pentax",
98 "Ricoh",
99 "Samsung",
100 "Sigma",
101 "Sony",
102 "NULL"
103 };
104 //--------------------------------------------------------------------
105
106
107 //####################################################################
108 // struct for holding camera/lens info and parameters
109 typedef struct
110 {
111 int ModifyFlags;
112 bool Inverse;
113 std::string Camera;
114 std::string CamMaker;
115 std::string Lens;
116 float Scale;
117 float Crop;
118 float Focal;
119 float Aperture;
120 float Distance;
121 lfLensType TargetGeom;
122 } MyLensfunOpts;
123 //--------------------------------------------------------------------
124 static MyLensfunOpts sLensfunParameters =
125 {
126 LF_MODIFY_DISTORTION,
127 false,
128 "",
129 "",
130 "",
131 0.0,
132 0,
133 0,
134 0,
135 1.0,
136 LF_RECTILINEAR
137 };
138 //--------------------------------------------------------------------
139
140
141 //####################################################################
142 // struct for storing camera/lens info and parameters
143 typedef struct
144 {
145 int ModifyFlags;
146 bool Inverse;
147 char Camera[255];
148 char CamMaker[255];
149 char Lens[255];
150 float Scale;
151 float Crop;
152 float Focal;
153 float Aperture;
154 float Distance;
155 lfLensType TargetGeom;
156 } MyLensfunOptStorage;
157 //--------------------------------------------------------------------
158 static MyLensfunOptStorage sLensfunParameterStorage =
159 {
160 LF_MODIFY_DISTORTION,
161 false,
162 "",
163 "",
164 "",
165 0.0,
166 0,
167 0,
168 0,
169 1.0,
170 LF_RECTILINEAR
171 };
172
173
174 // GIMP Plugin
175 GimpPlugInInfo PLUG_IN_INFO =
176 {
177 NULL,
178 NULL,
179 query,
180 run
181 };
182
MAIN()183 MAIN()
184
185
186 //####################################################################
187 // query() function
188 static void query (void)
189 {
190 static GimpParamDef args[] =
191 {
192 {
193 GIMP_PDB_INT32,
194 (char *)"run-mode",
195 (char *)"Run mode"
196 },
197 {
198 GIMP_PDB_IMAGE,
199 (char *)"image",
200 (char *)"Input image"
201 },
202 {
203 GIMP_PDB_DRAWABLE,
204 (char *)"drawable",
205 (char *)"Input drawable"
206 }
207 };
208
209 gimp_install_procedure (
210 "plug-in-lensfun",
211 "Correct lens distortion with lensfun",
212 "Correct lens distortion with lensfun",
213 "Sebastian Kraft",
214 "Copyright Sebastian Kraft",
215 "2010",
216 "_GimpLensfun...",
217 "RGB",
218 GIMP_PLUGIN,
219 G_N_ELEMENTS (args), 0,
220 args, NULL);
221
222 gimp_plugin_menu_register ("plug-in-lensfun",
223 "<Image>/Filters/Enhance");
224 }
225 //--------------------------------------------------------------------
226
227
228 //####################################################################
229 // Some helper functions
230
231 // Round float to integer value
roundfloat2int(float d)232 int roundfloat2int(float d)
233 {
234 return d<0?d-.5:d+.5;
235 }
236 //--------------------------------------------------------------------
StrReplace(std::string & str,const std::string & old,const std::string & newstr)237 void StrReplace(std::string& str, const std::string& old, const std::string& newstr)
238 {
239 size_t pos = 0;
240 while ((pos = str.find(old, pos)) != std::string::npos)
241 {
242 str.replace(pos, old.length(), newstr);
243 pos += newstr.length();
244 }
245 }
246 //--------------------------------------------------------------------
StrCompare(const std::string & str1,const std::string & str2,bool CaseSensitive=false)247 int StrCompare(const std::string& str1, const std::string& str2, bool CaseSensitive = false)
248 {
249 string s1 = str1;
250 string s2 = str2;
251
252 if (!CaseSensitive)
253 {
254 transform(s1.begin(), s1.end(), s1.begin(), ::tolower);
255 transform(s2.begin(), s2.end(), s2.begin(), ::tolower);
256 }
257
258 return s1.compare(s2);
259
260 }
261 //--------------------------------------------------------------------
262 #ifdef POSIX
timespec2llu(struct timespec * ts)263 unsigned long long int timespec2llu(struct timespec *ts) {
264 return (unsigned long long int) ( ((unsigned long long int)ts->tv_sec * 1000000000) + ts->tv_nsec);
265 }
266 #endif
267 //--------------------------------------------------------------------
268
269
270
271 //####################################################################
272 // Helper functions for printing debug output
273 #if DEBUG
PrintMount(const lfMount * mount)274 static void PrintMount (const lfMount *mount)
275 {
276 g_print ("Mount: %s\n", lf_mlstr_get (mount->Name));
277 if (mount->Compat)
278 for (int j = 0; mount->Compat [j]; j++)
279 g_print ("\tCompat: %s\n", mount->Compat [j]);
280 }
281 //--------------------------------------------------------------------
PrintCamera(const lfCamera * camera)282 static void PrintCamera (const lfCamera *camera)
283 {
284 g_print ("Camera: %s / %s %s%s%s\n",
285 lf_mlstr_get (camera->Maker),
286 lf_mlstr_get (camera->Model),
287 camera->Variant ? "(" : "",
288 camera->Variant ? lf_mlstr_get (camera->Variant) : "",
289 camera->Variant ? ")" : "");
290 g_print ("\tMount: %s\n", lf_db_mount_name (ldb, camera->Mount));
291 g_print ("\tCrop factor: %g\n", camera->CropFactor);
292 }
293 //--------------------------------------------------------------------
PrintLens(const lfLens * lens)294 static void PrintLens (const lfLens *lens)
295 {
296 g_print ("Lens: %s / %s\n",
297 lf_mlstr_get (lens->Maker),
298 lf_mlstr_get (lens->Model));
299 g_print ("\tCrop factor: %g\n", lens->CropFactor);
300 g_print ("\tFocal: %g-%g\n", lens->MinFocal, lens->MaxFocal);
301 g_print ("\tAperture: %g-%g\n", lens->MinAperture, lens->MaxAperture);
302 g_print ("\tCenter: %g,%g\n", lens->CenterX, lens->CenterY);
303 if (lens->Mounts)
304 for (int j = 0; lens->Mounts [j]; j++)
305 g_print ("\tMount: %s\n", lf_db_mount_name (ldb, lens->Mounts [j]));
306 }
307 //--------------------------------------------------------------------
PrintCameras(const lfCamera ** cameras)308 static void PrintCameras (const lfCamera **cameras)
309 {
310 if (cameras)
311 for (int i = 0; cameras [i]; i++)
312 {
313 g_print ("--- camera %d: ---\n", i + 1);
314 PrintCamera (cameras [i]);
315 }
316 else
317 g_print ("\t- failed\n");
318 }
319 //--------------------------------------------------------------------
PrintLenses(const lfLens ** lenses)320 static void PrintLenses (const lfLens **lenses)
321 {
322 if (lenses)
323 for (int i = 0; lenses [i]; i++)
324 {
325 g_print ("--- lens %d, score %d: ---\n", i + 1, lenses [i]->Score);
326 PrintLens (lenses [i]);
327 }
328 else
329 g_print ("\t- failed\n");
330 }
331 #endif
332 //--------------------------------------------------------------------
333
334
335 //####################################################################
336 // set dialog combo boxes to values
dialog_set_cboxes(string sNewMake,string sNewCamera,string sNewLens)337 static void dialog_set_cboxes( string sNewMake, string sNewCamera, string sNewLens) {
338
339 vector<string> vCameraList;
340 vector<string> vLensList;
341
342 const lfCamera** cameras = NULL;
343 const lfLens** lenses = NULL;
344 GtkTreeModel* store = NULL;
345
346 int iCurrMakerID = -1;
347 int iCurrCameraID = -1;
348 int iCurrLensId = -1;
349
350 sLensfunParameters.CamMaker.clear();
351 sLensfunParameters.Camera.clear();
352 sLensfunParameters.Lens.clear();
353
354 if (sNewMake.empty()==true)
355 return;
356
357 // try to match maker with predefined list
358 int iNumMakers = 0;
359 for (int i = 0; CameraMakers[i].compare("NULL")!=0; i++)
360 {
361 if (StrCompare(CameraMakers[i], sNewMake)==0) {
362 gtk_combo_box_set_active(GTK_COMBO_BOX(maker_combo), i);
363 iCurrMakerID = i;
364 }
365 iNumMakers++;
366 }
367
368 if (iCurrMakerID>=0)
369 sLensfunParameters.CamMaker = CameraMakers[iCurrMakerID];
370 else {
371 gtk_combo_box_append_text( GTK_COMBO_BOX(maker_combo), sNewMake.c_str());
372 gtk_combo_box_set_active(GTK_COMBO_BOX(maker_combo), iNumMakers);
373 iNumMakers++;
374 sLensfunParameters.CamMaker = sNewMake;
375 }
376
377 // clear camera/lens combobox
378 store = gtk_combo_box_get_model( GTK_COMBO_BOX(camera_combo) );
379 gtk_list_store_clear( GTK_LIST_STORE( store ) );
380 store = gtk_combo_box_get_model( GTK_COMBO_BOX(lens_combo) );
381 gtk_list_store_clear( GTK_LIST_STORE( store ) );
382
383 // get all cameras from maker out of database
384 cameras = ldb->FindCamerasExt (sLensfunParameters.CamMaker.c_str(), NULL, LF_SEARCH_LOOSE );
385 if (cameras) {
386 for (int i=0; cameras [i]; i++){
387 vCameraList.push_back(string(lf_mlstr_get(cameras[i]->Model)));
388 }
389 sort(vCameraList.begin(), vCameraList.end());
390 } else {
391 return;
392 }
393
394 for (unsigned int i=0; i<vCameraList.size(); i++)
395 {
396 gtk_combo_box_append_text( GTK_COMBO_BOX( camera_combo ), vCameraList[i].c_str());
397 // set to active if model matches current camera
398 if ((!sNewCamera.empty()) && (StrCompare(sNewCamera, vCameraList[i])==0)) {
399 gtk_combo_box_set_active(GTK_COMBO_BOX(camera_combo), i);
400 sLensfunParameters.Camera = sNewCamera;
401 }
402
403 if (StrCompare(string(lf_mlstr_get(cameras[i]->Model)), sNewCamera)==0)
404 iCurrCameraID = i;
405 }
406
407 // return if camera is unidentified
408 if (iCurrCameraID == -1)
409 {
410 lf_free(cameras);
411 return;
412 }
413
414 // find lenses for camera model
415 lenses = ldb->FindLenses (cameras[iCurrCameraID], NULL, NULL);
416 if (lenses) {
417 vLensList.clear();
418 for (int i = 0; lenses [i]; i++)
419 vLensList.push_back(string(lf_mlstr_get(lenses[i]->Model)));
420 sort(vLensList.begin(), vLensList.end());
421 } else {
422 lf_free(cameras);
423 return;
424 }
425
426 for (unsigned int i = 0; i<vLensList.size(); i++)
427 {
428 gtk_combo_box_append_text( GTK_COMBO_BOX( lens_combo ), (vLensList[i]).c_str());
429
430 // set active if lens matches current lens model
431 if ((!sNewLens.empty()) && (StrCompare(sNewLens, vLensList[i])==0)) {
432 gtk_combo_box_set_active(GTK_COMBO_BOX(lens_combo), i);
433 sLensfunParameters.Lens = sNewLens;
434 }
435
436 if (StrCompare(string(lf_mlstr_get(lenses[i]->Model)), sNewLens)==0)
437 iCurrLensId = i;
438 }
439
440 gtk_widget_set_sensitive(CorrTCA, false);
441 gtk_widget_set_sensitive(CorrVignetting, false);
442
443 if (iCurrLensId >= 0)
444 {
445 if (lenses[iCurrLensId]->CalibTCA != NULL)
446 gtk_widget_set_sensitive(CorrTCA, true);
447 if (lenses[iCurrLensId]->CalibVignetting != NULL)
448 gtk_widget_set_sensitive(CorrVignetting, true);
449 }
450
451 lf_free(lenses);
452 lf_free(cameras);
453 }
454 //--------------------------------------------------------------------
455
456 //####################################################################
457 // dialog callback functions
458 static void
maker_cb_changed(GtkComboBox * combo,gpointer data)459 maker_cb_changed( GtkComboBox *combo,
460 gpointer data )
461 {
462 if (!bComboBoxLock) {
463 bComboBoxLock = true;
464 dialog_set_cboxes(gtk_combo_box_get_active_text(GTK_COMBO_BOX(maker_combo)),
465 "",
466 "");
467 bComboBoxLock = false;
468 }
469 }
470 //--------------------------------------------------------------------
471 static void
camera_cb_changed(GtkComboBox * combo,gpointer data)472 camera_cb_changed( GtkComboBox *combo,
473 gpointer data )
474 {
475 if (!bComboBoxLock) {
476 bComboBoxLock = true;
477 dialog_set_cboxes(string(gtk_combo_box_get_active_text(GTK_COMBO_BOX(maker_combo))),
478 string(gtk_combo_box_get_active_text(GTK_COMBO_BOX(camera_combo))),
479 "");
480 bComboBoxLock = false;
481 }
482 }
483 //--------------------------------------------------------------------
484 static void
lens_cb_changed(GtkComboBox * combo,gpointer data)485 lens_cb_changed( GtkComboBox *combo,
486 gpointer data )
487 {
488 if (!bComboBoxLock) {
489 bComboBoxLock = true;
490 dialog_set_cboxes(string(gtk_combo_box_get_active_text(GTK_COMBO_BOX(maker_combo))),
491 string(gtk_combo_box_get_active_text(GTK_COMBO_BOX(camera_combo))),
492 string(gtk_combo_box_get_active_text(GTK_COMBO_BOX(lens_combo))));
493 bComboBoxLock = false;
494 }
495 }
496 //--------------------------------------------------------------------
497 static void
focal_changed(GtkComboBox * combo,gpointer data)498 focal_changed( GtkComboBox *combo,
499 gpointer data )
500 {
501 sLensfunParameters.Focal = (float) gtk_adjustment_get_value(GTK_ADJUSTMENT(data));
502 }
503 //--------------------------------------------------------------------
504 static void
aperture_changed(GtkComboBox * combo,gpointer data)505 aperture_changed( GtkComboBox *combo,
506 gpointer data )
507 {
508 sLensfunParameters.Aperture = (float) gtk_adjustment_get_value(GTK_ADJUSTMENT(data));
509 }
510 //--------------------------------------------------------------------
511 static void
scalecheck_changed(GtkCheckButton * togglebutn,gpointer data)512 scalecheck_changed( GtkCheckButton *togglebutn,
513 gpointer data )
514 {
515 sLensfunParameters.Scale = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutn));
516 }
517 //--------------------------------------------------------------------
518 static void
modify_changed(GtkCheckButton * togglebutn,gpointer data)519 modify_changed( GtkCheckButton *togglebutn,
520 gpointer data )
521 {
522 sLensfunParameters.ModifyFlags = 0;
523 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(CorrDistortion))
524 && GTK_WIDGET_SENSITIVE(CorrDistortion))
525 sLensfunParameters.ModifyFlags |= LF_MODIFY_DISTORTION;
526
527 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(CorrTCA))
528 && GTK_WIDGET_SENSITIVE(CorrTCA))
529 sLensfunParameters.ModifyFlags |= LF_MODIFY_TCA;
530
531 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(CorrVignetting))
532 && GTK_WIDGET_SENSITIVE(CorrVignetting))
533 sLensfunParameters.ModifyFlags |= LF_MODIFY_VIGNETTING;
534 }//--------------------------------------------------------------------
535
536
537 //####################################################################
538 // Create gtk dialog window
create_dialog_window(GimpDrawable * drawable)539 static gboolean create_dialog_window (GimpDrawable *drawable)
540 {
541 GtkWidget *dialog;
542 GtkWidget *main_vbox;
543 GtkWidget *frame, *frame2;
544 GtkWidget *camera_label, *lens_label, *maker_label;
545 GtkWidget *focal_label, *aperture_label;
546 GtkWidget *scalecheck;
547
548 GtkWidget *spinbutton;
549 GtkObject *spinbutton_adj;
550 GtkWidget *spinbutton_aperture;
551 GtkObject *spinbutton_aperture_adj;
552 GtkWidget *frame_label, *frame_label2;
553 GtkWidget *table, *table2;
554 gboolean run;
555
556 gint iTableRow = 0;
557
558 gimp_ui_init ("mylensfun", FALSE);
559
560 dialog = gimp_dialog_new ("GIMP-Lensfun (v" VERSIONSTR ")", "mylensfun",
561 NULL, GTK_DIALOG_MODAL ,
562 gimp_standard_help_func, "plug-in-lensfun",
563 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
564 GTK_STOCK_OK, GTK_RESPONSE_OK,
565 NULL);
566
567 main_vbox = gtk_vbox_new (FALSE, 6);
568 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox);
569 gtk_widget_show (main_vbox);
570
571 frame = gtk_frame_new (NULL);
572 gtk_widget_show (frame);
573 gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
574 gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
575
576 frame_label = gtk_label_new ("Camera/Lens Parameters");
577 gtk_widget_show (frame_label);
578 gtk_frame_set_label_widget (GTK_FRAME (frame), frame_label);
579 gtk_label_set_use_markup (GTK_LABEL (frame_label), TRUE);
580
581 table = gtk_table_new(6, 2, TRUE);
582 gtk_table_set_homogeneous(GTK_TABLE(table), false);
583 gtk_table_set_row_spacings(GTK_TABLE(table), 2);
584 gtk_table_set_col_spacings(GTK_TABLE(table), 2);
585 gtk_container_set_border_width(GTK_CONTAINER(table), 10);
586
587 // camera maker
588 maker_label = gtk_label_new ("Maker:");
589 gtk_misc_set_alignment(GTK_MISC(maker_label),0.0,0.5);
590 gtk_widget_show (maker_label);
591 gtk_table_attach(GTK_TABLE(table), maker_label, 0, 1, iTableRow, iTableRow+1, GTK_FILL, GTK_FILL, 0,0 );
592
593 maker_combo = gtk_combo_box_new_text();
594 gtk_widget_show (maker_combo);
595
596 for (int i = 0; StrCompare(CameraMakers[i], "NULL")!=0; i++)
597 {
598 gtk_combo_box_append_text( GTK_COMBO_BOX( maker_combo ), CameraMakers[i].c_str());
599 }
600
601 gtk_table_attach_defaults(GTK_TABLE(table), maker_combo, 1, 2, iTableRow, iTableRow+1 );
602
603 iTableRow++;
604
605 // camera
606 camera_label = gtk_label_new ("Camera:");
607 gtk_misc_set_alignment(GTK_MISC(camera_label),0.0,0.5);
608 gtk_widget_show (camera_label);
609 gtk_table_attach(GTK_TABLE(table), camera_label, 0, 1, iTableRow, iTableRow+1, GTK_FILL, GTK_FILL, 0,0 );
610
611 camera_combo = gtk_combo_box_new_text();
612 gtk_widget_show (camera_combo);
613
614 gtk_table_attach_defaults(GTK_TABLE(table), camera_combo, 1,2, iTableRow, iTableRow+1 );
615
616 iTableRow++;
617
618 // lens
619 lens_label = gtk_label_new ("Lens:");
620 gtk_misc_set_alignment(GTK_MISC(lens_label),0.0,0.5);
621 gtk_widget_show (lens_label);
622 gtk_table_attach_defaults(GTK_TABLE(table), lens_label, 0,1,iTableRow, iTableRow+1 );
623
624 lens_combo = gtk_combo_box_new_text();
625 gtk_widget_show (lens_combo);
626
627 gtk_table_attach_defaults(GTK_TABLE(table), lens_combo, 1,2,iTableRow, iTableRow+1 );
628 iTableRow++;
629
630 // focal length
631 focal_label = gtk_label_new("Focal length (mm):");
632 gtk_misc_set_alignment(GTK_MISC(focal_label),0.0,0.5);
633 gtk_widget_show (focal_label);
634 gtk_table_attach_defaults(GTK_TABLE(table), focal_label, 0,1,iTableRow, iTableRow+1 );
635
636 spinbutton_adj = gtk_adjustment_new (sLensfunParameters.Focal, 0, 5000, 0.1, 0, 0);
637 spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton_adj), 2, 1);
638 gtk_widget_show (spinbutton);
639 gtk_table_attach_defaults(GTK_TABLE(table), spinbutton, 1,2,iTableRow, iTableRow+1 );
640 iTableRow++;
641
642 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
643
644 // aperture
645 aperture_label = gtk_label_new("Aperture:");
646 gtk_misc_set_alignment(GTK_MISC(aperture_label),0.0,0.5);
647 gtk_widget_show (focal_label);
648 gtk_table_attach_defaults(GTK_TABLE(table), aperture_label, 0,1,iTableRow, iTableRow+1 );
649
650 spinbutton_aperture_adj = gtk_adjustment_new (sLensfunParameters.Aperture, 0, 128, 0.1, 0, 0);
651 spinbutton_aperture = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton_aperture_adj), 2, 1);
652 gtk_widget_show (spinbutton_aperture);
653 gtk_table_attach_defaults(GTK_TABLE(table), spinbutton_aperture, 1,2,iTableRow, iTableRow+1 );
654 iTableRow++;
655
656 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton_aperture), TRUE);
657
658 gtk_container_add (GTK_CONTAINER (frame), table);
659 gtk_widget_show_all(table);
660
661 frame2 = gtk_frame_new (NULL);
662 gtk_widget_show (frame2);
663 gtk_box_pack_start (GTK_BOX (main_vbox), frame2, TRUE, TRUE, 0);
664 gtk_container_set_border_width (GTK_CONTAINER (frame2), 6);
665
666 frame_label2 = gtk_label_new ("Processing Parameters");
667 gtk_widget_show (frame_label2);
668 gtk_frame_set_label_widget (GTK_FRAME (frame2), frame_label2);
669 gtk_label_set_use_markup (GTK_LABEL (frame_label2), TRUE);
670
671 table2 = gtk_table_new(6, 2, TRUE);
672 gtk_table_set_homogeneous(GTK_TABLE(table2), false);
673 gtk_table_set_row_spacings(GTK_TABLE(table2), 2);
674 gtk_table_set_col_spacings(GTK_TABLE(table2), 2);
675 gtk_container_set_border_width(GTK_CONTAINER(table2), 10);
676
677 iTableRow = 0;
678
679 // scale to fit checkbox
680 scalecheck = gtk_check_button_new_with_label("Scale to fit");
681 //gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), FALSE);
682 gtk_widget_show (scalecheck);
683 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(scalecheck), !sLensfunParameters.Scale);
684 gtk_table_attach_defaults(GTK_TABLE(table2), scalecheck, 1,2,iTableRow, iTableRow+1 );
685 iTableRow++;
686
687 // enable distortion correction
688 CorrDistortion = gtk_check_button_new_with_label("Distortion");
689 //gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), FALSE);
690 gtk_widget_show (CorrDistortion);
691 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(CorrDistortion), true);
692 gtk_table_attach_defaults(GTK_TABLE(table2), CorrDistortion, 1,2,iTableRow, iTableRow+1 );
693 iTableRow++;
694
695 // enable vignetting correction
696 CorrVignetting = gtk_check_button_new_with_label("Vignetting");
697 //gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), FALSE);
698 gtk_widget_show (CorrVignetting);
699 gtk_widget_set_sensitive(CorrVignetting, false);
700 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(CorrVignetting), false);
701 gtk_table_attach_defaults(GTK_TABLE(table2), CorrVignetting, 1,2,iTableRow, iTableRow+1 );
702 iTableRow++;
703
704 // enable TCA correction
705 CorrTCA = gtk_check_button_new_with_label("Chromatic Aberration");
706 //gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), FALSE);
707 gtk_widget_show (CorrTCA);
708 gtk_widget_set_sensitive(CorrTCA, false);
709 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(CorrTCA), false);
710 gtk_table_attach_defaults(GTK_TABLE(table2), CorrTCA, 1,2,iTableRow, iTableRow+1 );
711 iTableRow++;
712
713 gtk_container_add (GTK_CONTAINER (frame2), table2);
714 gtk_widget_show_all(table2);
715
716 // try to set combo boxes to exif
717 dialog_set_cboxes(sLensfunParameters.CamMaker,
718 sLensfunParameters.Camera,
719 sLensfunParameters.Lens);
720
721 // connect signals
722 g_signal_connect( G_OBJECT( maker_combo ), "changed",
723 G_CALLBACK( maker_cb_changed ), NULL );
724 g_signal_connect( G_OBJECT( camera_combo ), "changed",
725 G_CALLBACK( camera_cb_changed ), NULL );
726 g_signal_connect( G_OBJECT( lens_combo ), "changed",
727 G_CALLBACK( lens_cb_changed ), NULL );
728 g_signal_connect (spinbutton_adj, "value_changed",
729 G_CALLBACK (focal_changed), spinbutton_adj);
730 g_signal_connect (spinbutton_aperture_adj, "value_changed",
731 G_CALLBACK (aperture_changed), spinbutton_aperture_adj);
732
733 g_signal_connect( G_OBJECT( scalecheck ), "toggled",
734 G_CALLBACK( scalecheck_changed ), NULL );
735 g_signal_connect( G_OBJECT( CorrDistortion ), "toggled",
736 G_CALLBACK( modify_changed ), NULL );
737 g_signal_connect( G_OBJECT( CorrTCA ), "toggled",
738 G_CALLBACK( modify_changed ), NULL );
739 g_signal_connect( G_OBJECT( CorrVignetting ), "toggled",
740 G_CALLBACK( modify_changed ), NULL );
741
742 // show and run
743 gtk_widget_show (dialog);
744 run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
745
746 gtk_widget_destroy (dialog);
747 return run;
748 }
749 //--------------------------------------------------------------------
750
751
752 //####################################################################
753 // Interpolation functions
Lanczos(float x)754 inline float Lanczos(float x)
755 {
756 if ( (x<FLT_MIN) && (x>-FLT_MIN) )
757 return 1.0f;
758
759 if ( (x >= cLanczosWidth) || (x <= (-1)*cLanczosWidth) )
760 return 0.0f;
761
762 float xpi = x * static_cast<float>(M_PI);
763 return ( cLanczosWidth * sin(xpi) * sin(xpi/cLanczosWidth) ) / ( xpi*xpi );
764 }
765 //--------------------------------------------------------------------
InitInterpolation(glInterpolationType intType)766 void InitInterpolation(glInterpolationType intType)
767 {
768 switch(intType) {
769 case GL_INTERPOL_NN: break;
770 case GL_INTERPOL_BL: break;
771 case GL_INTERPOL_LZ:
772 for (int i = -cLanczosWidth*cLanczosTableRes; i < cLanczosWidth*cLanczosTableRes; i++) {
773 LanczosLUT[i + cLanczosWidth*cLanczosTableRes] = Lanczos(static_cast<float>(i)/static_cast<float>(cLanczosTableRes));
774 }
775
776 break;
777 }
778 }
779 //--------------------------------------------------------------------
InterpolateLanczos(guchar * ImgBuffer,gint w,gint h,gint channels,float xpos,float ypos,int chan)780 inline int InterpolateLanczos(guchar *ImgBuffer, gint w, gint h, gint channels, float xpos, float ypos, int chan)
781 {
782
783 int xl = int(xpos);
784 int yl = int(ypos);
785 float y = 0.0f;
786 float norm = 0.0f;
787 float L = 0.0f;
788
789 // border checking
790 if ((xl-cLanczosWidth+1 < 0) ||
791 (xl+cLanczosWidth >= w) ||
792 (yl-cLanczosWidth+1 < 0) ||
793 (yl+cLanczosWidth >= h))
794 {
795 return 0;
796 }
797
798 // convolve with lanczos kernel
799 for (int i = xl-cLanczosWidth+1; i < xl+cLanczosWidth; i++) {
800 for (int j = yl-cLanczosWidth+1; j < yl+cLanczosWidth; j++) {
801 L = LanczosLUT[ (xpos - static_cast<float>(i))*static_cast<float>(cLanczosTableRes) + static_cast<float>(cLanczosWidth*cLanczosTableRes) ]
802 * LanczosLUT[ (ypos - static_cast<float>(j))*static_cast<float>(cLanczosTableRes) + static_cast<float>(cLanczosWidth*cLanczosTableRes) ];
803 // L = Lanczos(xpos - static_cast<float>(i))
804 // * Lanczos(ypos - static_cast<float>(j));
805 y += static_cast<float>(ImgBuffer[ (channels*w*j) + (i*channels) + chan ]) * L;
806 norm += L;
807 }
808 }
809 // normalize
810 y = y / norm;
811
812 // clip
813 if (y>255)
814 y = 255;
815 if (y<0)
816 y = 0;
817
818 // round to integer and return
819 return roundfloat2int(y);
820 }
821 //--------------------------------------------------------------------
InterpolateLinear(guchar * ImgBuffer,gint w,gint h,gint channels,float xpos,float ypos,int chan)822 inline int InterpolateLinear(guchar *ImgBuffer, gint w, gint h, gint channels, float xpos, float ypos, int chan)
823 {
824 // interpolated values in x and y direction
825 float x1, x2, y;
826
827 // surrounding integer rounded coordinates
828 int xl, xr, yu, yl;
829
830 xl = floor(xpos);
831 xr = ceil (xpos + 1e-10);
832 yu = floor(ypos);
833 yl = ceil (ypos + 1e-10);
834
835 // border checking
836 if ((xl < 0) ||
837 (xr >= w) ||
838 (yu < 0) ||
839 (yl >= h))
840 {
841 return 0;
842 }
843
844
845 float px1y1 = (float) ImgBuffer[ (channels*w*yu) + (xl*channels) + chan ];
846 float px1y2 = (float) ImgBuffer[ (channels*w*yl) + (xl*channels) + chan ];
847 float px2y1 = (float) ImgBuffer[ (channels*w*yu) + (xr*channels) + chan ];
848 float px2y2 = (float) ImgBuffer[ (channels*w*yl) + (xr*channels) + chan ];
849
850 x1 = (static_cast<float>(xr) - xpos)*px1y1 + (xpos - static_cast<float>(xl))*px2y1;
851 x2 = (static_cast<float>(xr) - xpos)*px1y2 + (xpos - static_cast<float>(xl))*px2y2;
852
853 y = (ypos - static_cast<float>(yu))*x2 + (static_cast<float>(yl) - ypos)*x1;
854
855 return roundfloat2int(y);
856 }
857 //--------------------------------------------------------------------
InterpolateNearest(guchar * ImgBuffer,gint w,gint h,gint channels,float xpos,float ypos,int chan)858 inline int InterpolateNearest(guchar *ImgBuffer, gint w, gint h, gint channels, float xpos, float ypos, int chan)
859 {
860 int x = roundfloat2int(xpos);
861 int y = roundfloat2int(ypos);
862
863
864 // border checking
865 if ((x < 0) ||
866 (x >= w) ||
867 (y < 0) ||
868 (y >= h))
869 {
870 return 0;
871 }
872
873 return ImgBuffer[ (channels*w*y) + (x*channels) + chan ];
874 }
875 //--------------------------------------------------------------------
876
877
878 //####################################################################
879 // Processing
process_image(GimpDrawable * drawable)880 static void process_image (GimpDrawable *drawable) {
881 gint channels;
882 gint x1, y1, x2, y2, imgwidth, imgheight;
883
884 GimpPixelRgn rgn_in, rgn_out;
885 guchar *ImgBuffer;
886 guchar *ImgBufferOut;
887
888 if ((sLensfunParameters.CamMaker.length()==0) ||
889 (sLensfunParameters.Camera.length()==0) ||
890 (sLensfunParameters.Lens.length()==0)) {
891 return;
892 }
893
894 #ifdef POSIX
895 struct timespec profiling_start, profiling_stop;
896 #endif
897
898 // get image size
899 gimp_drawable_mask_bounds (drawable->drawable_id,
900 &x1, &y1,
901 &x2, &y2);
902 imgwidth = x2-x1;
903 imgheight = y2-y1;
904
905 // get number of channels
906 channels = gimp_drawable_bpp (drawable->drawable_id);
907
908 gimp_pixel_rgn_init (&rgn_in,
909 drawable,
910 x1, y1,
911 imgwidth, imgheight,
912 FALSE, FALSE);
913 gimp_pixel_rgn_init (&rgn_out,
914 drawable,
915 x1, y1,
916 imgwidth, imgheight,
917 TRUE, TRUE);
918
919 //Init input and output buffer
920 ImgBuffer = g_new (guchar, channels * (imgwidth+1) * (imgheight+1));
921 ImgBufferOut = g_new (guchar, channels * (imgwidth+1) * (imgheight+1));
922 InitInterpolation(GL_INTERPOL_LZ);
923
924 // Copy pixel data from GIMP to internal buffer
925 gimp_pixel_rgn_get_rect (&rgn_in, ImgBuffer, x1, y1, imgwidth, imgheight);
926
927 if (sLensfunParameters.Scale<1) {
928 sLensfunParameters.ModifyFlags |= LF_MODIFY_SCALE;
929 }
930
931 const lfCamera **cameras = ldb->FindCamerasExt (sLensfunParameters.CamMaker.c_str(), sLensfunParameters.Camera.c_str());
932 sLensfunParameters.Crop = cameras[0]->CropFactor;
933
934 const lfLens **lenses = ldb->FindLenses (cameras[0], NULL, sLensfunParameters.Lens.c_str());
935
936 if (DEBUG) {
937 g_print("\nApplied settings:\n");
938 g_print("\tCamera: %s, %s\n", cameras[0]->Maker, cameras[0]->Model);
939 g_print("\tLens: %s\n", lenses[0]->Model);
940 g_print("\tFocal Length: %f\n", sLensfunParameters.Focal);
941 g_print("\tF-Stop: %f\n", sLensfunParameters.Aperture);
942 g_print("\tCrop Factor: %f\n", sLensfunParameters.Crop);
943 g_print("\tScale: %f\n", sLensfunParameters.Scale);
944
945 #ifdef POSIX
946 clock_gettime(CLOCK_REALTIME, &profiling_start);
947 #endif
948 }
949
950 //init lensfun modifier
951 lfModifier *mod = new lfModifier (lenses[0], sLensfunParameters.Crop, imgwidth, imgheight);
952 mod->Initialize ( lenses[0], LF_PF_U8, sLensfunParameters.Focal,
953 sLensfunParameters.Aperture, sLensfunParameters.Distance, sLensfunParameters.Scale, sLensfunParameters.TargetGeom,
954 sLensfunParameters.ModifyFlags, sLensfunParameters.Inverse);
955
956 int iRowCount = 0;
957 #pragma omp parallel
958 {
959 // buffer containing undistorted coordinates for one row
960 float *UndistCoord = g_new (float, imgwidth*2*channels);
961
962 //main loop for processing, iterate through rows
963 #pragma omp for
964 for (int i = 0; i < imgheight; i++)
965 {
966 mod->ApplyColorModification( &ImgBuffer[(channels*imgwidth*i)],
967 0, i, imgwidth, 1,
968 LF_CR_3(RED, GREEN, BLUE),
969 channels*imgwidth);
970
971 mod->ApplySubpixelGeometryDistortion (0, i, imgwidth, 1, UndistCoord);
972
973 float* UndistIter = UndistCoord;
974 guchar *OutputBuffer = &ImgBufferOut[channels*imgwidth*i];
975 //iterate through subpixels in one row
976 for (int j = 0; j < imgwidth*channels; j += channels)
977 {
978 *OutputBuffer = InterpolateLanczos(ImgBuffer, imgwidth, imgheight, channels, UndistIter [0], UndistIter [1], 0);
979 OutputBuffer++;
980 *OutputBuffer = InterpolateLanczos(ImgBuffer, imgwidth, imgheight, channels, UndistIter [2], UndistIter [3], 1);
981 OutputBuffer++;
982 *OutputBuffer = InterpolateLanczos(ImgBuffer, imgwidth, imgheight, channels, UndistIter [4], UndistIter [5], 2);
983 OutputBuffer++;
984
985 // move pointer to next pixel
986 UndistIter += 2 * 3;
987 }
988 #pragma omp atomic
989 iRowCount++;
990 //update progress bar only every N rows
991 if (iRowCount % 200 == 0) {
992 #pragma omp critical
993 {
994 gimp_progress_update ((gdouble) (iRowCount - y1) / (gdouble) (imgheight));
995 }
996 }
997 }
998 g_free(UndistCoord);
999 }
1000
1001 delete mod;
1002
1003 #ifdef POSIX
1004 if (DEBUG) {
1005 clock_gettime(CLOCK_REALTIME, &profiling_stop);
1006 unsigned long long int time_diff = timespec2llu(&profiling_stop) - timespec2llu(&profiling_start);
1007 g_print("\nPerformance: %12llu ns, %d pixel -> %llu ns/pixel\n", time_diff, imgwidth*imgheight, time_diff / (imgwidth*imgheight));
1008 }
1009 #endif
1010
1011 //write data back to gimp
1012 gimp_pixel_rgn_set_rect (&rgn_out, ImgBufferOut, x1, y1, imgwidth, imgheight);
1013
1014 gimp_drawable_flush (drawable);
1015 gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
1016 gimp_drawable_update (drawable->drawable_id,
1017 x1, y1,
1018 imgwidth, imgheight);
1019 gimp_displays_flush ();
1020 gimp_drawable_detach (drawable);
1021
1022 // free memory
1023 g_free(ImgBufferOut);
1024 g_free(ImgBuffer);
1025
1026 lf_free(lenses);
1027 lf_free(cameras);
1028 }
1029 //--------------------------------------------------------------------
1030
1031
1032 //####################################################################
1033 // Read camera and lens info from exif and try to find in database
1034 //
read_opts_from_exif(const char * filename)1035 static int read_opts_from_exif(const char *filename) {
1036
1037 Exiv2::Image::AutoPtr Exiv2image;
1038 Exiv2::ExifData exifData;
1039
1040 const lfCamera **cameras = 0;
1041 const lfCamera *camera = 0;
1042
1043 const lfLens **lenses = 0;
1044 const lfLens *lens = 0;
1045 std::string LensNameMN;
1046
1047 if (DEBUG) {
1048 g_print ("Reading exif data...");
1049 }
1050
1051 try {
1052 // read exif from file
1053 Exiv2image = Exiv2::ImageFactory::open(string(filename));
1054 Exiv2image.get();
1055 Exiv2image->readMetadata();
1056 exifData = Exiv2image->exifData();
1057
1058 if (exifData.empty()) {
1059 if (DEBUG) {
1060 g_print ("no exif data found. \n");
1061 }
1062 return -1;
1063 }
1064 }
1065 catch (Exiv2::AnyError& e) {
1066 if (DEBUG) {
1067 g_print ("exception on reading data. \n");
1068 }
1069 return -1;
1070 }
1071
1072 // search database for camera
1073 cameras = ldb->FindCameras (exifData["Exif.Image.Make"].toString().c_str(), exifData["Exif.Image.Model"].toString().c_str());
1074 if (cameras) {
1075 camera = cameras [0];
1076 sLensfunParameters.Crop = camera->CropFactor;
1077 sLensfunParameters.Camera = string(lf_mlstr_get(camera->Model));
1078 sLensfunParameters.CamMaker = string(lf_mlstr_get(camera->Maker));
1079 } else {
1080 sLensfunParameters.CamMaker = exifData["Exif.Image.Make"].toString();
1081 }
1082 //PrintCameras(cameras, ldb);
1083
1084 //Get lensID
1085 string CamMaker = exifData["Exif.Image.Make"].toString();
1086 transform(CamMaker.begin(), CamMaker.end(),CamMaker.begin(), ::tolower);
1087 string MakerNoteKey;
1088
1089 //Select special MakerNote Tag for lens depending on Maker
1090 if ((CamMaker.find("pentax"))!=string::npos) {
1091 MakerNoteKey = "Exif.Pentax.LensType";
1092 }
1093 else if ((CamMaker.find("canon"))!=string::npos) {
1094 MakerNoteKey = "Exif.CanonCs.LensType";
1095 }
1096 else if ((CamMaker.find("minolta"))!=string::npos) {
1097 MakerNoteKey = "Exif.Minolta.LensID";
1098 }
1099 else if ((CamMaker.find("nikon"))!=string::npos) {
1100 MakerNoteKey = "Exif.NikonLd3.LensIDNumber";
1101 if (exifData[MakerNoteKey].toString().size()==0) {
1102 MakerNoteKey = "Exif.NikonLd2.LensIDNumber";
1103 }
1104 if (exifData[MakerNoteKey].toString().size()==0) {
1105 MakerNoteKey = "Exif.NikonLd1.LensIDNumber";
1106 }
1107 }
1108 else if ((CamMaker.find("olympus"))!=string::npos) {
1109 MakerNoteKey = "Exif.OlympusEq.LensType";
1110 }
1111 else {
1112 //Use default lens model tag for all other makers
1113 MakerNoteKey = "Exif.Photo.LensModel";
1114 }
1115
1116 //Decode Lens ID
1117 if ((MakerNoteKey.size()>0) && (exifData[MakerNoteKey].toString().size()>0)) {
1118 Exiv2::ExifKey ek(MakerNoteKey);
1119 Exiv2::ExifData::const_iterator md = exifData.findKey(ek);
1120 if (md != exifData.end()) {
1121 LensNameMN = md->print(&exifData);
1122
1123 //Modify some lens names for better searching in lfDatabase
1124 if ((CamMaker.find("nikon"))!=std::string::npos) {
1125 StrReplace(LensNameMN, "Nikon", "");
1126 StrReplace(LensNameMN, "Zoom-Nikkor", "");
1127 }
1128 }
1129 }
1130
1131 if (camera) {
1132 if (LensNameMN.size()>8) { // only take lens names with significant length
1133 lenses = ldb->FindLenses (camera, NULL, LensNameMN.c_str());
1134 } else {
1135 lenses = ldb->FindLenses (camera, NULL, NULL);
1136 }
1137 if (lenses) {
1138 lens = lenses[0];
1139 sLensfunParameters.Lens = string(lf_mlstr_get(lens->Model));
1140 }
1141 lf_free (lenses);
1142 }
1143 lf_free (cameras);
1144
1145 sLensfunParameters.Focal = exifData["Exif.Photo.FocalLength"].toFloat();
1146 sLensfunParameters.Aperture = exifData["Exif.Photo.FNumber"].toFloat();
1147
1148 if (DEBUG) {
1149 g_print("\nExif Data:\n");
1150 g_print("\tCamera: %s, %s\n", sLensfunParameters.CamMaker.c_str(), sLensfunParameters.Camera.c_str());
1151 g_print("\tLens: %s\n", sLensfunParameters.Lens.c_str());
1152 g_print("\tFocal Length: %f\n", sLensfunParameters.Focal);
1153 g_print("\tF-Stop: %f\n", sLensfunParameters.Aperture);
1154 g_print("\tCrop Factor: %f\n", sLensfunParameters.Crop);
1155 g_print("\tScale: %f\n", sLensfunParameters.Scale);
1156 }
1157
1158 return 0;
1159 }
1160 //--------------------------------------------------------------------
1161
1162
1163 //####################################################################
1164 // store and load parameters and settings to/from gimp_data_storage
loadSettings()1165 static void loadSettings() {
1166
1167 gimp_get_data ("plug-in-gimplensfun", &sLensfunParameterStorage);
1168
1169 sLensfunParameters.ModifyFlags = sLensfunParameterStorage.ModifyFlags;
1170 sLensfunParameters.Inverse = sLensfunParameterStorage.Inverse;
1171 if (strlen(sLensfunParameterStorage.Camera)>0)
1172 sLensfunParameters.Camera = std::string(sLensfunParameterStorage.Camera);
1173 if (strlen(sLensfunParameterStorage.CamMaker)>0)
1174 sLensfunParameters.CamMaker = std::string(sLensfunParameterStorage.CamMaker);
1175 if (strlen(sLensfunParameterStorage.Lens)>0)
1176 sLensfunParameters.Lens = std::string(sLensfunParameterStorage.Lens);
1177 sLensfunParameters.Scale = sLensfunParameterStorage.Scale;
1178 sLensfunParameters.Crop = sLensfunParameterStorage.Crop;
1179 sLensfunParameters.Focal = sLensfunParameterStorage.Focal;
1180 sLensfunParameters.Aperture = sLensfunParameterStorage.Aperture;
1181 sLensfunParameters.Distance = sLensfunParameterStorage.Distance;
1182 sLensfunParameters.TargetGeom = sLensfunParameterStorage.TargetGeom;
1183 }
1184 //--------------------------------------------------------------------
1185
storeSettings()1186 static void storeSettings() {
1187
1188 sLensfunParameterStorage.ModifyFlags = sLensfunParameters.ModifyFlags;
1189 sLensfunParameterStorage.Inverse = sLensfunParameters.Inverse;
1190 strcpy( sLensfunParameterStorage.Camera, sLensfunParameters.Camera.c_str() );
1191 strcpy( sLensfunParameterStorage.CamMaker, sLensfunParameters.CamMaker.c_str() );
1192 strcpy( sLensfunParameterStorage.Lens, sLensfunParameters.Lens.c_str() );
1193 sLensfunParameterStorage.Scale = sLensfunParameters.Scale;
1194 sLensfunParameterStorage.Crop = sLensfunParameters.Crop;
1195 sLensfunParameterStorage.Focal = sLensfunParameters.Focal;
1196 sLensfunParameterStorage.Aperture = sLensfunParameters.Aperture;
1197 sLensfunParameterStorage.Distance = sLensfunParameters.Distance;
1198 sLensfunParameterStorage.TargetGeom = sLensfunParameters.TargetGeom;
1199
1200 gimp_set_data ("plug-in-gimplensfun", &sLensfunParameterStorage, sizeof (sLensfunParameterStorage));
1201 }
1202 //--------------------------------------------------------------------
1203
1204
1205 //####################################################################
1206 // Run()
1207 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)1208 run (const gchar* name,
1209 gint nparams,
1210 const GimpParam* param,
1211 gint* nreturn_vals,
1212 GimpParam** return_vals)
1213 {
1214 static GimpParam values[1];
1215 GimpPDBStatusType status = GIMP_PDB_SUCCESS;
1216 gint32 imageID;
1217 GimpRunMode run_mode;
1218 GimpDrawable *drawable;
1219
1220 /* Setting mandatory output values */
1221 *nreturn_vals = 1;
1222 *return_vals = values;
1223
1224 values[0].type = GIMP_PDB_STATUS;
1225 values[0].data.d_status = status;
1226
1227 drawable = gimp_drawable_get (param[2].data.d_drawable);
1228
1229 gimp_progress_init ("Lensfun correction...");
1230
1231 imageID = param[1].data.d_drawable;
1232
1233 if (DEBUG) g_print ("Loading database...");
1234 //Load lensfun database
1235 ldb = new lfDatabase ();
1236 if (ldb->Load () != LF_NO_ERROR) {
1237 if (DEBUG) g_print ("failed!\n");
1238 } else {
1239 if (DEBUG) g_print ("OK\n");
1240 }
1241
1242 // read exif data
1243 const gchar *filename = gimp_image_get_filename(imageID);
1244 if (DEBUG) g_print ("Image file path: %s\n", filename);
1245
1246 if ((filename == NULL) || (read_opts_from_exif(filename) != 0)) {
1247 loadSettings();
1248 }
1249
1250 run_mode = GimpRunMode(param[0].data.d_int32);
1251 if (run_mode == GIMP_RUN_INTERACTIVE)
1252 {
1253 if (DEBUG) g_print ("Creating dialog...\n");
1254 /* Display the dialog */
1255 if (create_dialog_window (drawable)) {
1256 process_image(drawable);
1257 }
1258 }
1259 else
1260 {
1261 /* If run_mode is non-interactive, we use the configuration
1262 * from read_opts_from_exif. If that fails, we use the stored settings
1263 * (loadSettings()), e.g. the settings that have been made in the last
1264 * interactive use of the plugin. One day, all settings should be
1265 * available as arguments in non-interactive mode.
1266 */
1267 process_image(drawable);
1268 }
1269
1270 storeSettings();
1271
1272 delete ldb;
1273 }
1274