1 /*
2 SANE EPSON backend
3 Copyright (C) 2001, 2005, 2008 SEIKO EPSON Corporation
4
5 Date Author Reason
6 06/01/2001 N.Sasaki New
7
8 This file is part of the `iscan' program.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
24 As a special exception, the copyright holders give permission
25 to link the code of this program with the esmod library and
26 distribute linked combinations including the two. You must obey
27 the GNU General Public License in all respects for all of the
28 code used other then esmod.
29 */
30
31 #include <config.h>
32
33 #include "gettext.h"
34 #define _(msg_id) gettext (msg_id)
35
36 /*------------------------------------------------------------*/
37 #include <gtk/gtk.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 /*------------------------------------------------------------*/
43 #include "pisa_view_manager.h"
44 #include "pisa_gamma_correction.h"
45 #include "xpm_data.h"
46 #include "pisa_tool.h"
47 #include "pisa_error.h"
48
49 #define RADIUS 3
50 #define MIN_DISTANCE 8
51 #define NUM_POINTS 13
52
53 /*------------------------------------------------------------*/
54 char ** g_gamma_xpm [ ] =
55 {
56 gamma_m_xpm, // mono
57 gamma_r_xpm, // red
58 gamma_g_xpm, // green
59 gamma_b_xpm, // blue
60 };
61
62 /*------------------------------------------------------------*/
switch_page(GtkNotebook * notebook,GtkNotebookPage * page,gint page_num,gpointer * data)63 static void switch_page ( GtkNotebook * notebook,
64 GtkNotebookPage * page,
65 gint page_num,
66 gpointer * data )
67 {
68 gamma_correction * gamma_cls;
69
70 notebook = notebook;
71 page = page;
72
73 gamma_cls = ( gamma_correction * ) data;
74
75 gamma_cls->change_page ( page_num );
76 }
77
78 /*------------------------------------------------------------*/
click_reset(GtkWidget * widget,gpointer * data)79 static void click_reset ( GtkWidget * widget,
80 gpointer * data )
81 {
82 gamma_correction * gamma_cls;
83
84 widget = widget;
85
86 gamma_cls = ( gamma_correction * ) data;
87
88 gamma_cls->reset ( 0 );
89
90 ::g_view_manager->update_lut ( );
91
92 preview_window *prev_cls =
93 (preview_window *) ::g_view_manager->get_window_cls (ID_WINDOW_PREV);
94
95 prev_cls->update_img ( );
96 }
97
98 /*------------------------------------------------------------*/
gamma_curve_event(GtkWidget * widget,GdkEvent * event,gpointer * data)99 static gint gamma_curve_event ( GtkWidget * widget,
100 GdkEvent * event,
101 gpointer * data )
102 {
103 gamma_correction * gamma_cls;
104
105 gamma_cls = ( gamma_correction * ) data;
106
107 return gamma_cls->event ( widget, event );
108 }
109
110 /*------------------------------------------------------------*/
init(void)111 int gamma_correction::init ( void )
112 {
113 int i;
114
115 m_page = 0;
116
117 for ( i = 0; i < WG_GAMMA_NUM; i++ )
118 m_widget [ i ] = 0;
119
120 for ( i = 0; i < 4; i++ )
121 {
122 m_pixmap [ i ] = 0;
123 m_active [ i ] = 0;
124
125 reset_points ( i );
126 }
127
128 m_basis [ 0 ] [ 0 ] = -0.5; m_basis [ 0 ] [ 1 ] = 1.5; m_basis [ 0 ] [ 2 ] = -1.5; m_basis [ 0 ] [ 3 ] = 0.5;
129 m_basis [ 1 ] [ 0 ] = 1.0; m_basis [ 1 ] [ 1 ] = -2.5; m_basis [ 1 ] [ 2 ] = 2.0; m_basis [ 1 ] [ 3 ] = -0.5;
130 m_basis [ 2 ] [ 0 ] = -0.5; m_basis [ 2 ] [ 1 ] = 0.0; m_basis [ 2 ] [ 2 ] = 0.5; m_basis [ 2 ] [ 3 ] = 0.0;
131 m_basis [ 3 ] [ 0 ] = 0.0; m_basis [ 3 ] [ 1 ] = 1.0; m_basis [ 3 ] [ 2 ] = 0.0; m_basis [ 3 ] [ 3 ] = 0.0;
132
133 for ( i = 0; i < 2; i++ )
134 m_cursor [ i ] = 0;
135
136 return PISA_ERR_SUCCESS;
137 }
138
139 /*------------------------------------------------------------*/
create_window(GtkWidget * parent)140 GtkWidget * gamma_correction::create_window ( GtkWidget * parent )
141 {
142 GtkWidget * frame;
143 GtkWidget * vbox;
144 GtkWidget * widget;
145
146 frame = ::gtk_frame_new ( _( "Tone Correction" ) );
147 ::gtk_container_border_width ( GTK_CONTAINER ( frame ), 5 );
148
149 vbox = ::gtk_vbox_new ( FALSE, 2 );
150 ::gtk_container_add ( GTK_CONTAINER ( frame ), vbox );
151 ::gtk_widget_show ( vbox );
152
153 widget = create_gamma_notebook ( parent );
154 ::gtk_box_pack_start ( GTK_BOX ( vbox ), widget, FALSE, FALSE, 0 );
155 ::gtk_widget_show ( widget );
156
157 widget = create_reset_button ( );
158 ::gtk_box_pack_start ( GTK_BOX ( vbox ), widget, FALSE, FALSE, 0 );
159 ::gtk_widget_show ( widget );
160
161 m_cursor [ PISA_CS_GM_X ] = ::gdk_cursor_new ( GDK_X_CURSOR );
162 m_cursor [ PISA_CS_GM_FLEUR ] = ::gdk_cursor_new ( GDK_FLEUR );
163 m_cursor [ PISA_CS_GM_TCROSS ] = ::gdk_cursor_new ( GDK_TCROSS );
164
165 return frame;
166 }
167
168 /*------------------------------------------------------------*/
close_window(int destroy)169 int gamma_correction::close_window ( int destroy )
170 {
171 int i;
172
173 destroy = destroy;
174
175 for ( i = 0; i < 2; i++ )
176 {
177 if ( m_cursor [ i ] )
178 ::gdk_cursor_destroy ( m_cursor [ i ] );
179 m_cursor [ i ] = 0;
180 }
181
182 return PISA_ERR_SUCCESS;
183 }
184
185 /*------------------------------------------------------------*/
sensitive(int is_prev_img)186 void gamma_correction::sensitive ( int is_prev_img )
187 {
188 gboolean enable_rgb, enable_r_g_b;
189
190 settings set = g_view_manager->get_settings ();
191
192 // grayout
193 switch ( set.imgtype.pixeltype )
194 {
195 case PISA_PT_RGB:
196 enable_rgb = TRUE;
197 enable_r_g_b = TRUE;
198 break;
199 case PISA_PT_GRAY:
200 enable_rgb = TRUE;
201 enable_r_g_b = FALSE;
202 break;
203 case PISA_PT_BW:
204 enable_rgb = FALSE;
205 enable_r_g_b = FALSE;
206 break;
207 default:
208 return;
209 }
210
211 if ( is_prev_img == 0 )
212 enable_rgb = enable_r_g_b = FALSE;
213
214 m_active [ 0 ] = enable_rgb;
215 m_active [ 1 ] = enable_r_g_b;
216 m_active [ 2 ] = enable_r_g_b;
217 m_active [ 3 ] = enable_r_g_b;
218
219 ::gtk_widget_set_sensitive ( m_widget [ WG_GAMMA_TAB_RGB ], enable_rgb );
220 ::gtk_widget_set_sensitive ( m_widget [ WG_GAMMA_TAB_RED ], enable_r_g_b );
221 ::gtk_widget_set_sensitive ( m_widget [ WG_GAMMA_TAB_GRN ], enable_r_g_b );
222 ::gtk_widget_set_sensitive ( m_widget [ WG_GAMMA_TAB_BLU ], enable_r_g_b );
223
224 ::gtk_widget_set_sensitive ( m_widget [ WG_GAMMA_BOX_RGB ], enable_rgb );
225 ::gtk_widget_set_sensitive ( m_widget [ WG_GAMMA_BOX_RED ], enable_r_g_b );
226 ::gtk_widget_set_sensitive ( m_widget [ WG_GAMMA_BOX_GRN ], enable_r_g_b );
227 ::gtk_widget_set_sensitive ( m_widget [ WG_GAMMA_BOX_BLU ], enable_r_g_b );
228
229 if ( enable_rgb == TRUE && enable_r_g_b == FALSE )
230 ::gtk_notebook_set_page ( GTK_NOTEBOOK ( m_widget [ WG_GAMMA_NOTE ] ),
231 GAMMA_RGB );
232
233 ::gtk_widget_set_sensitive ( m_widget [ WG_GAMMA_RESET ], m_active [ m_page ] );
234
235 update_gamma ( );
236 }
237
238 /*------------------------------------------------------------*/
change_page(int page)239 void gamma_correction::change_page ( int page )
240 {
241 m_page = page;
242
243 ::gtk_widget_set_sensitive ( m_widget [ WG_GAMMA_RESET ], m_active [ m_page ] );
244
245 }
246
247
248 /*------------------------------------------------------------*/
reset(int all)249 void gamma_correction::reset ( int all )
250 {
251 if ( all == 1 )
252 {
253 int i;
254
255 for ( i = 0; i < 4; i++ )
256 reset_points ( i );
257 }
258 else
259 reset_points ( m_page );
260
261 calculate_curve ( );
262 update_gamma ( );
263 }
264
265 /*------------------------------------------------------------*/
event(GtkWidget * widget,GdkEvent * event)266 gint gamma_correction::event ( GtkWidget * widget, GdkEvent * event )
267 {
268 static int cursor_type = PISA_CS_GM_FLEUR;
269 int new_type;
270 GdkEventButton * bevent;
271 GdkEventMotion * mevent;
272 gint tx, ty, x, y;
273 gint i, distance, closest_point;
274
275 ::gdk_window_get_pointer ( m_drawarea [ m_page ]->window,
276 & tx, & ty, 0 );
277 x = CLAMP ( ( tx - RADIUS ), 0, GAMMA_WIDTH - 1 );
278 y = CLAMP ( ( ty - RADIUS ), 0, GAMMA_HEIGHT - 1 );
279
280 distance = G_MAXINT;
281 closest_point = 0;
282
283 for ( i = 0; i < NUM_POINTS; i++ )
284 {
285 if ( m_points [ m_page ] [ i ] [ 0 ] != -1 )
286 if ( ::abs ( x - m_points [ m_page ] [ i ] [ 0 ] ) < distance )
287 {
288 distance = ::abs ( x - m_points [ m_page ] [ i ] [ 0 ] );
289 closest_point = i;
290 }
291 }
292
293 if ( distance > MIN_DISTANCE )
294 closest_point = ( x + 8 ) / 16;
295
296 switch ( event->type )
297 {
298 case GDK_EXPOSE:
299 if ( m_pixmap [ m_page ] == 0 )
300 m_pixmap [ m_page ] = ::gdk_pixmap_new ( m_drawarea [ m_page ]->window,
301 GAMMA_WIDTH + RADIUS * 2,
302 GAMMA_HEIGHT + RADIUS * 2,
303 -1 );
304 update_gamma ( );
305 break;
306
307 case GDK_BUTTON_PRESS:
308 bevent = ( GdkEventButton * ) event;
309 new_type = PISA_CS_GM_TCROSS;
310
311 m_leftmost = -1;
312 for ( i = closest_point - 1; i >= 0; i-- )
313 if ( m_points [ m_page ] [ i ] [ 0 ] != -1 )
314 {
315 m_leftmost = m_points [ m_page ] [ i ] [ 0 ];
316 break;
317 }
318 m_rightmost = GAMMA_WIDTH;
319 for ( i = closest_point + 1; i < NUM_POINTS; i++ )
320 if ( m_points [ m_page ] [ i ] [ 0 ] != -1 )
321 {
322 m_rightmost = m_points [ m_page ] [ i ][ 0 ];
323 break;
324 }
325
326 m_grabpoint = closest_point;
327 m_points [ m_page ] [ m_grabpoint ] [ 0 ] = x;
328 m_points [ m_page ] [ m_grabpoint ] [ 1 ] = GAMMA_HEIGHT - 1 - y;
329
330 calculate_curve ( );
331 update_gamma ( );
332 gtk_grab_add ( widget );
333 break;
334
335 case GDK_BUTTON_RELEASE:
336 new_type = PISA_CS_GM_FLEUR;
337 m_grabpoint = -1;
338 gtk_grab_remove ( widget );
339 ::g_view_manager->update_lut ( );
340 {
341 preview_window *prev_cls =
342 (preview_window *) ::g_view_manager->get_window_cls (ID_WINDOW_PREV);
343
344 prev_cls->update_img ( );
345 }
346 break;
347
348 case GDK_MOTION_NOTIFY:
349 mevent = ( GdkEventMotion * ) event;
350
351 if ( mevent->is_hint )
352 {
353 mevent->x = tx;
354 mevent->y = ty;
355 }
356
357 if ( m_grabpoint == -1 )
358 {
359 if ( m_points [ m_page ] [ closest_point ] [ 0 ] != -1 )
360 new_type = PISA_CS_GM_FLEUR;
361 else
362 new_type = PISA_CS_GM_TCROSS;
363 }
364 else
365 {
366 new_type = PISA_CS_GM_TCROSS;
367
368 m_points [ m_page ] [ m_grabpoint ] [ 0 ] = -1;
369
370 if ( x > m_leftmost && x < m_rightmost )
371 {
372 closest_point = ( x + 8 ) / 16;
373 if ( m_points [ m_page ] [ closest_point ] [ 0 ] == -1 )
374 m_grabpoint = closest_point;
375
376 m_points [ m_page ] [ m_grabpoint ] [ 0 ] = x;
377 m_points [ m_page ] [ m_grabpoint ] [ 1 ] = GAMMA_HEIGHT - 1 - y;
378 }
379 calculate_curve ( );
380 update_gamma ( );
381 }
382
383 if ( new_type != cursor_type )
384 {
385 cursor_type = new_type;
386 ::gdk_window_set_cursor ( m_drawarea [ m_page ]->window,
387 m_cursor [ cursor_type ] );
388 }
389
390 break;
391
392 default:
393 break;
394 }
395
396 return FALSE;
397 }
398
399 /*------------------------------------------------------------*/
create_gamma_notebook(GtkWidget * parent)400 GtkWidget * gamma_correction::create_gamma_notebook ( GtkWidget * parent )
401 {
402 GtkWidget * hbox;
403 GtkWidget * notebook;
404 GtkWidget * vbox;
405 GtkWidget * img;
406 GtkWidget * gamma_curve;
407 int i;
408
409 hbox = ::gtk_hbox_new ( FALSE, 2 );
410
411 notebook = ::gtk_notebook_new ( );
412 ::gtk_container_border_width ( GTK_CONTAINER ( notebook ), 2 );
413 ::gtk_box_pack_start ( GTK_BOX ( hbox ), notebook, TRUE, FALSE, 0 );
414
415 for ( i = 0; i < 4; i++ )
416 {
417 vbox = gtk_vbox_new ( FALSE, 5 );
418
419 img = ::xpm2widget ( parent, g_gamma_xpm [ i ] );
420
421 m_widget [ i ] = img;
422
423 ::gtk_notebook_append_page ( GTK_NOTEBOOK ( notebook ), vbox, img );
424 ::gtk_widget_show ( vbox );
425
426 gamma_curve = create_gamma_curve ( i );
427
428 m_widget [ i + 4 ] = gamma_curve;
429
430 ::gtk_box_pack_start ( GTK_BOX ( vbox ), gamma_curve, FALSE, FALSE, 0 );
431 ::gtk_widget_show ( gamma_curve );
432 }
433
434 ::gtk_signal_connect ( GTK_OBJECT ( notebook ),
435 "switch_page",
436 GTK_SIGNAL_FUNC ( ::switch_page ),
437 this );
438
439 ::gtk_widget_show ( notebook );
440
441 m_widget [ WG_GAMMA_NOTE ] = notebook;
442
443 return hbox;
444 }
445
446 /*------------------------------------------------------------*/
create_gamma_curve(int i)447 GtkWidget * gamma_correction::create_gamma_curve ( int i )
448 {
449 GtkWidget * frame;
450 GtkWidget * gamma_curve;
451
452 frame = ::gtk_frame_new ( 0 );
453 ::gtk_frame_set_shadow_type ( GTK_FRAME ( frame ), GTK_SHADOW_ETCHED_IN );
454
455 gamma_curve = ::gtk_drawing_area_new ( );
456 ::gtk_drawing_area_size ( GTK_DRAWING_AREA ( gamma_curve ),
457 GAMMA_WIDTH + RADIUS * 2,
458 GAMMA_HEIGHT + RADIUS * 2 );
459
460 ::gtk_widget_set_events ( gamma_curve,
461 GDK_EXPOSURE_MASK |
462 GDK_POINTER_MOTION_MASK |
463 GDK_POINTER_MOTION_HINT_MASK |
464 GDK_ENTER_NOTIFY_MASK |
465 GDK_BUTTON_PRESS_MASK |
466 GDK_BUTTON_RELEASE_MASK |
467 GDK_BUTTON1_MOTION_MASK );
468
469 m_drawarea [ i ] = gamma_curve;
470
471 ::gtk_signal_connect ( GTK_OBJECT ( gamma_curve ), "event",
472 GTK_SIGNAL_FUNC ( gamma_curve_event ), this );
473
474
475 ::gtk_container_add ( GTK_CONTAINER ( frame ), gamma_curve );
476
477 ::gtk_widget_show ( gamma_curve );
478
479 return frame;
480 }
481
482 /*------------------------------------------------------------*/
create_reset_button(void)483 GtkWidget * gamma_correction::create_reset_button ( void )
484 {
485 GtkWidget * hbox;
486 GtkWidget * button;
487
488 hbox = ::gtk_hbox_new ( FALSE, 5 );
489 ::gtk_container_border_width ( GTK_CONTAINER ( hbox ), 5 );
490
491 button = ::gtk_button_new_with_label ( _( " Reset " ) );
492 ::gtk_box_pack_start ( GTK_BOX ( hbox ), button, TRUE, FALSE, 0 );
493 ::gtk_signal_connect ( GTK_OBJECT ( button ), "clicked",
494 GTK_SIGNAL_FUNC ( ::click_reset ), this );
495 ::gtk_widget_show ( button );
496
497 m_widget [ WG_GAMMA_RESET ] = button;
498
499 return hbox;
500 }
501
502 /*------------------------------------------------------------*/
reset_points(int i)503 void gamma_correction::reset_points ( int i )
504 {
505 int j;
506
507 m_grabpoint = -1;
508
509 for ( j = 0; j < NUM_POINTS; j++ )
510 {
511 m_points [ i ] [ j ] [ 0 ] = -1;
512 m_points [ i ] [ j ] [ 1 ] = -1;
513 }
514
515 for ( j = 0; j < GAMMA_WIDTH; j++ )
516 m_curve [ i ] [ j ] = j;
517
518 m_points [ i ] [ 0 ] [ 0 ] = 0;
519 m_points [ i ] [ 0 ] [ 1 ] = 0;
520 m_points [ i ] [ NUM_POINTS - 1 ] [ 0 ] = GAMMA_WIDTH - 1;
521 m_points [ i ] [ NUM_POINTS - 1 ] [ 1 ] = GAMMA_HEIGHT - 1;
522 }
523
524 /*------------------------------------------------------------*/
update_gamma(void)525 void gamma_correction::update_gamma ( void )
526 {
527 int i;
528 GdkPoint points [ GAMMA_WIDTH ];
529 GdkGC * gc;
530
531 if ( m_pixmap [ m_page ] == 0 )
532 return;
533
534 // clear the pixmap
535 ::gdk_draw_rectangle ( m_pixmap [ m_page ],
536 m_drawarea [ m_page ]->style->bg_gc [ GTK_STATE_NORMAL ],
537 TRUE, 0, 0,
538 GAMMA_WIDTH + RADIUS * 2, GAMMA_HEIGHT + RADIUS * 2 );
539
540 // draw the grid line
541 for ( i = 0; i < 13; i++ )
542 {
543 ::gdk_draw_line ( m_pixmap [ m_page ],
544 m_drawarea [ m_page ]->style->dark_gc [ GTK_STATE_NORMAL ],
545 RADIUS, i * ( GAMMA_HEIGHT / 12 ) + RADIUS,
546 GAMMA_WIDTH + RADIUS, i * ( GAMMA_HEIGHT / 12 ) + RADIUS );
547 ::gdk_draw_line ( m_pixmap [ m_page ],
548 m_drawarea [ m_page ]->style->dark_gc [ GTK_STATE_NORMAL ],
549 i * ( GAMMA_WIDTH / 12 ) + RADIUS, RADIUS,
550 i * ( GAMMA_WIDTH / 12 ) + RADIUS, GAMMA_HEIGHT + RADIUS );
551 }
552
553 if ( m_active [ m_page ] )
554 gc = m_drawarea [ m_page ]->style->black_gc;
555 else
556 gc = m_drawarea [ m_page ]->style->dark_gc [ GTK_STATE_NORMAL ];
557
558 // draw the curve
559 for ( i = 0; i < GAMMA_WIDTH; i++ )
560 {
561 points [ i ].x = i + RADIUS;
562 points [ i ].y = ( GAMMA_HEIGHT ) - m_curve [ m_page ] [ i ] + RADIUS;
563 }
564
565 ::gdk_draw_points ( m_pixmap [ m_page ],
566 gc, points, GAMMA_WIDTH );
567
568 // draw the points
569 for ( i = 0; i < NUM_POINTS; i++ )
570 {
571 if ( m_points [ m_page ] [ i ] [ 0 ] != -1 )
572 ::gdk_draw_arc ( m_pixmap [ m_page ],
573 gc,
574 TRUE,
575 m_points [ m_page ] [ i ] [ 0 ],
576 ( GAMMA_HEIGHT - 1 ) - m_points [ m_page ] [ i ] [ 1 ],
577 RADIUS * 2, RADIUS * 2, 0, 23040 );
578 }
579
580 ::gdk_draw_pixmap ( m_drawarea [ m_page ]->window,
581 m_drawarea [ m_page ]->style->black_gc,
582 m_pixmap [ m_page ],
583 0, 0, 0, 0, GAMMA_WIDTH + RADIUS * 2,
584 GAMMA_HEIGHT + RADIUS * 2 );
585 return;
586 }
587
588 /*------------------------------------------------------------*/
calculate_curve(void)589 void gamma_correction::calculate_curve ( void )
590 {
591 int i, num;
592 int p1, p2, p3, p4;
593 int points [ NUM_POINTS ];
594 marquee * marq;
595
596 num = 0;
597
598 for ( i = 0; i < NUM_POINTS; i++ )
599 if ( m_points [ m_page ] [ i ] [ 0 ] != -1 )
600 points [ num++ ] = i;
601
602 if ( 0 < num )
603 {
604 for ( i = 0; i < m_points [ m_page ] [ points [ 0 ] ] [ 0 ]; i++ )
605 {
606 m_curve [ m_page ] [ i ] =
607 m_points [ m_page ] [ points [ 0 ] ] [ 1 ];
608 }
609
610 for ( i = m_points [ m_page ] [ points [ num - 1 ] ] [ 0 ]; i < GAMMA_WIDTH; i++ )
611 {
612 m_curve [ m_page ] [ i ] =
613 m_points [ m_page ] [ points [ num - 1 ] ] [ 1 ];
614 }
615 }
616
617 for ( i = 0; i < num - 1; i++ )
618 {
619 p1 = ( i == 0 ) ? points [ i ] : points [ ( i - 1 ) ];
620 p2 = points [ i ];
621 p3 = points [ ( i + 1 ) ];
622 p4 = ( i == ( num - 2 ) ) ? points [ ( num - 1 ) ] : points [ ( i + 2 ) ];
623
624 plot_curve ( p1, p2, p3, p4 );
625 }
626
627 marq = & g_view_manager->get_marquee ();
628
629 for ( i = 0; i < 256; i++ )
630 marq->gamma_table [ m_page ] [ i ] =
631 255 * ( m_curve [ m_page ] [ 191 * i / 255 ] ) / ( GAMMA_WIDTH - 1 );
632 }
633
634 /*------------------------------------------------------------*/
plot_curve(int p1,int p2,int p3,int p4)635 void gamma_correction::plot_curve ( int p1, int p2, int p3, int p4 )
636 {
637 matrix geometry;
638 matrix tmp1, tmp2;
639 matrix deltas;
640 double x, dx, dx2, dx3;
641 double y, dy, dy2, dy3;
642 double d, d2, d3;
643 int lastx, lasty;
644 int newx, newy;
645 int i;
646
647 for ( i = 0; i < 4; i++ )
648 {
649 geometry [ i ] [ 0 ] = 0;
650 geometry [ i ] [ 1 ] = 0;
651 geometry [ i ] [ 2 ] = 0;
652 geometry [ i ] [ 3 ] = 0;
653 }
654
655 for ( i = 0; i < 2; i++ )
656 {
657 geometry [ 0 ] [ i ] = m_points [ m_page ] [ p1 ] [ i ];
658 geometry [ 1 ] [ i ] = m_points [ m_page ] [ p2 ] [ i ];
659 geometry [ 2 ] [ i ] = m_points [ m_page ] [ p3 ] [ i ];
660 geometry [ 3 ] [ i ] = m_points [ m_page ] [ p4 ] [ i ];
661 }
662
663 d = 1.0 / 1000;
664 d2 = d * d;
665 d3 = d * d * d;
666
667 tmp2 [ 0 ] [ 0 ] = 0; tmp2 [ 0 ] [ 1 ] = 0; tmp2 [ 0 ] [ 2 ] = 0; tmp2 [ 0 ] [ 3 ] = 1;
668 tmp2 [ 1 ] [ 0 ] = d3; tmp2 [ 1 ] [ 1 ] = d2; tmp2 [ 1 ] [ 2 ] = d; tmp2 [ 1 ] [ 3 ] = 0;
669 tmp2 [ 2 ] [ 0 ] = 6 * d3; tmp2 [ 2 ] [ 1 ] = 2 * d2; tmp2 [ 2 ] [ 2 ] = 0; tmp2 [ 2 ] [ 3 ] = 0;
670 tmp2 [ 3 ] [ 0 ] = 6 * d3; tmp2 [ 3 ] [ 1 ] = 0; tmp2 [ 3 ] [ 2 ] = 0; tmp2 [ 3 ] [ 3 ] = 0;
671
672 compose_curve ( m_basis, geometry, tmp1 );
673
674 compose_curve ( tmp2, tmp1, deltas );
675
676 x = deltas [ 0 ] [ 0 ];
677 dx = deltas [ 1 ] [ 0 ];
678 dx2 = deltas [ 2 ] [ 0 ];
679 dx3 = deltas [ 3 ] [ 0 ];
680
681 y = deltas [ 0 ] [ 1 ];
682 dy = deltas [ 1 ] [ 1 ];
683 dy2 = deltas [ 2 ] [ 1 ];
684 dy3 = deltas [ 3 ] [ 1 ];
685
686 lastx = ( int ) ( CLAMP ( x, 0, GAMMA_WIDTH - 1 ) );
687 lasty = ( int ) ( CLAMP ( y, 0, GAMMA_HEIGHT - 1 ));
688
689 m_curve [ m_page ] [ lastx ] = lasty;
690
691 for ( i = 0; i < 1000; i++ )
692 {
693 x += dx;
694 dx += dx2;
695 dx2 += dx3;
696
697 y += dy;
698 dy += dy2;
699 dy2 += dy3;
700
701 newx = CLAMP ( int ( x + 0.5 ), 0, GAMMA_WIDTH - 1 );
702 newy = CLAMP ( int ( y + 0.5 ), 0, GAMMA_HEIGHT - 1 );
703
704 if ( ( lastx != newx ) || ( lasty != newy ) )
705 m_curve [ m_page ] [ newx ] = newy;
706
707 lastx = newx;
708 lasty = newy;
709 }
710 }
711
712 /*------------------------------------------------------------*/
compose_curve(matrix a,matrix b,matrix ab)713 void gamma_correction::compose_curve ( matrix a, matrix b, matrix ab )
714 {
715 int i, j;
716
717 for ( i = 0; i < 4; i++ )
718 {
719 for ( j = 0; j < 4; j++ )
720 {
721 ab [ i ] [ j ] = ( a [ i ] [ 0 ] * b [ 0 ] [ j ] +
722 a [ i ] [ 1 ] * b [ 1 ] [ j ] +
723 a [ i ] [ 2 ] * b [ 2 ] [ j ] +
724 a [ i ] [ 3 ] * b [ 3 ] [ j ] );
725 }
726 }
727 }
728