1 /*
2 * Sharpen filters for GIMP - The GNU Image Manipulation Program
3 *
4 * Copyright 1997-1998 Michael Sweet (mike@easysw.com)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include "config.h"
22
23 #include <string.h>
24
25 #include <libgimp/gimp.h>
26 #include <libgimp/gimpui.h>
27
28 #include "libgimp/stdplugins-intl.h"
29
30 /*
31 * Constants...
32 */
33
34 #define PLUG_IN_PROC "plug-in-sharpen"
35 #define PLUG_IN_BINARY "sharpen"
36 #define PLUG_IN_ROLE "gimp-sharpen"
37 #define PLUG_IN_VERSION "1.4.2 - 3 June 1998"
38 #define SCALE_WIDTH 100
39
40 /*
41 * Local functions...
42 */
43
44 static void query (void);
45 static void run (const gchar *name,
46 gint nparams,
47 const GimpParam *param,
48 gint *nreturn_vals,
49 GimpParam **returm_vals);
50
51 static void compute_luts (void);
52 static void sharpen (GimpDrawable *drawable);
53
54 static gboolean sharpen_dialog (GimpDrawable *drawable);
55
56 static void preview_update (GimpPreview *preview,
57 GimpDrawable *drawable);
58
59 typedef gint32 intneg;
60 typedef gint32 intpos;
61
62 static void gray_filter (int width, guchar *src, guchar *dst, intneg *neg0,
63 intneg *neg1, intneg *neg2);
64 static void graya_filter (int width, guchar *src, guchar *dst, intneg *neg0,
65 intneg *neg1, intneg *neg2);
66 static void rgb_filter (int width, guchar *src, guchar *dst, intneg *neg0,
67 intneg *neg1, intneg *neg2);
68 static void rgba_filter (int width, guchar *src, guchar *dst, intneg *neg0,
69 intneg *neg1, intneg *neg2);
70
71
72 /*
73 * Globals...
74 */
75
76 const GimpPlugInInfo PLUG_IN_INFO =
77 {
78 NULL, /* init_proc */
79 NULL, /* quit_proc */
80 query, /* query_proc */
81 run /* run_proc */
82 };
83
84 typedef struct
85 {
86 gint sharpen_percent;
87 } SharpenParams;
88
89 static SharpenParams sharpen_params =
90 {
91 10
92 };
93
94 static intneg neg_lut[256]; /* Negative coefficient LUT */
95 static intpos pos_lut[256]; /* Positive coefficient LUT */
96
97
MAIN()98 MAIN ()
99
100 static void
101 query (void)
102 {
103 static const GimpParamDef args[] =
104 {
105 { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
106 { GIMP_PDB_IMAGE, "image", "Input image" },
107 { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
108 { GIMP_PDB_INT32, "percent", "Percent sharpening (default = 10)" }
109 };
110
111 gimp_install_procedure (PLUG_IN_PROC,
112 N_("Make image sharper "
113 "(less powerful than Unsharp Mask)"),
114 "This plug-in selectively performs a convolution "
115 "filter on an image.",
116 "Michael Sweet <mike@easysw.com>",
117 "Copyright 1997-1998 by Michael Sweet",
118 PLUG_IN_VERSION,
119 N_("_Sharpen..."),
120 "RGB*, GRAY*",
121 GIMP_PLUGIN,
122 G_N_ELEMENTS (args), 0,
123 args, NULL);
124 }
125
126 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)127 run (const gchar *name,
128 gint nparams,
129 const GimpParam *param,
130 gint *nreturn_vals,
131 GimpParam **return_vals)
132 {
133 static GimpParam values[1]; /* Return values */
134 GimpRunMode run_mode; /* Current run mode */
135 GimpPDBStatusType status; /* Return status */
136 GimpDrawable *drawable; /* Current image */
137
138 /*
139 * Initialize parameter data...
140 */
141
142 status = GIMP_PDB_SUCCESS;
143 run_mode = param[0].data.d_int32;
144
145 INIT_I18N ();
146
147 *nreturn_vals = 1;
148 *return_vals = values;
149
150 values[0].type = GIMP_PDB_STATUS;
151 values[0].data.d_status = status;
152
153 /*
154 * Get drawable information...
155 */
156
157 drawable = gimp_drawable_get (param[2].data.d_drawable);
158 gimp_tile_cache_ntiles (2 * drawable->ntile_cols);
159
160
161 /*
162 * See how we will run
163 */
164
165 switch (run_mode)
166 {
167 case GIMP_RUN_INTERACTIVE:
168 /*
169 * Possibly retrieve data...
170 */
171 gimp_get_data (PLUG_IN_PROC, &sharpen_params);
172
173 /*
174 * Get information from the dialog...
175 */
176 if (!sharpen_dialog (drawable))
177 return;
178 break;
179
180 case GIMP_RUN_NONINTERACTIVE:
181 /*
182 * Make sure all the arguments are present...
183 */
184 if (nparams != 4)
185 status = GIMP_PDB_CALLING_ERROR;
186 else
187 sharpen_params.sharpen_percent = param[3].data.d_int32;
188 break;
189
190 case GIMP_RUN_WITH_LAST_VALS:
191 /*
192 * Possibly retrieve data...
193 */
194 gimp_get_data (PLUG_IN_PROC, &sharpen_params);
195 break;
196
197 default:
198 status = GIMP_PDB_CALLING_ERROR;
199 break;
200 }
201
202 /*
203 * Sharpen the image...
204 */
205
206 if (status == GIMP_PDB_SUCCESS)
207 {
208 if ((gimp_drawable_is_rgb (drawable->drawable_id) ||
209 gimp_drawable_is_gray (drawable->drawable_id)))
210 {
211 /*
212 * Run!
213 */
214 sharpen (drawable);
215
216 /*
217 * If run mode is interactive, flush displays...
218 */
219 if (run_mode != GIMP_RUN_NONINTERACTIVE)
220 gimp_displays_flush ();
221
222 /*
223 * Store data...
224 */
225 if (run_mode == GIMP_RUN_INTERACTIVE)
226 gimp_set_data (PLUG_IN_PROC,
227 &sharpen_params, sizeof (SharpenParams));
228 }
229 else
230 status = GIMP_PDB_EXECUTION_ERROR;
231 }
232
233 /*
234 * Reset the current run status...
235 */
236 values[0].data.d_status = status;
237
238 /*
239 * Detach from the drawable...
240 */
241 gimp_drawable_detach (drawable);
242 }
243
244
245 static void
compute_luts(void)246 compute_luts (void)
247 {
248 gint i; /* Looping var */
249 gint fact; /* 1 - sharpness */
250
251 fact = 100 - sharpen_params.sharpen_percent;
252 if (fact < 1)
253 fact = 1;
254
255 for (i = 0; i < 256; i ++)
256 {
257 pos_lut[i] = 800 * i / fact;
258 neg_lut[i] = (4 + pos_lut[i] - (i << 3)) >> 3;
259 }
260 }
261
262 /*
263 * 'sharpen()' - Sharpen an image using a convolution filter.
264 */
265
266 static void
sharpen(GimpDrawable * drawable)267 sharpen (GimpDrawable *drawable)
268 {
269 GimpPixelRgn src_rgn; /* Source image region */
270 GimpPixelRgn dst_rgn; /* Destination image region */
271 guchar *src_rows[4]; /* Source pixel rows */
272 guchar *src_ptr; /* Current source pixel */
273 guchar *dst_row; /* Destination pixel row */
274 intneg *neg_rows[4]; /* Negative coefficient rows */
275 intneg *neg_ptr; /* Current negative coefficient */
276 gint i; /* Looping vars */
277 gint y; /* Current location in image */
278 gint row; /* Current row in src_rows */
279 gint count; /* Current number of filled src_rows */
280 gint width; /* Byte width of the image */
281 gint x1; /* Selection bounds */
282 gint y1;
283 gint y2;
284 gint sel_width; /* Selection width */
285 gint sel_height; /* Selection height */
286 gint img_bpp; /* Bytes-per-pixel in image */
287 void (*filter)(int, guchar *, guchar *, intneg *, intneg *, intneg *);
288
289 filter = NULL;
290
291 if (! gimp_drawable_mask_intersect (drawable->drawable_id,
292 &x1, &y1, &sel_width, &sel_height))
293 return;
294
295 y2 = y1 + sel_height;
296
297 img_bpp = gimp_drawable_bpp (drawable->drawable_id);
298
299 /*
300 * Let the user know what we're doing...
301 */
302 gimp_progress_init (_("Sharpening"));
303
304 /*
305 * Setup for filter...
306 */
307
308 gimp_pixel_rgn_init (&src_rgn, drawable,
309 x1, y1, sel_width, sel_height, FALSE, FALSE);
310 gimp_pixel_rgn_init (&dst_rgn, drawable,
311 x1, y1, sel_width, sel_height, TRUE, TRUE);
312
313 compute_luts ();
314
315 width = sel_width * img_bpp;
316
317 for (row = 0; row < 4; row ++)
318 {
319 src_rows[row] = g_new (guchar, width);
320 neg_rows[row] = g_new (intneg, width);
321 }
322
323 dst_row = g_new (guchar, width);
324
325 /*
326 * Pre-load the first row for the filter...
327 */
328
329 gimp_pixel_rgn_get_row (&src_rgn, src_rows[0], x1, y1, sel_width);
330
331 for (i = width, src_ptr = src_rows[0], neg_ptr = neg_rows[0];
332 i > 0;
333 i --, src_ptr ++, neg_ptr ++)
334 *neg_ptr = neg_lut[*src_ptr];
335
336 row = 1;
337 count = 1;
338
339 /*
340 * Select the filter...
341 */
342
343 switch (img_bpp)
344 {
345 case 1 :
346 filter = gray_filter;
347 break;
348 case 2 :
349 filter = graya_filter;
350 break;
351 case 3 :
352 filter = rgb_filter;
353 break;
354 case 4 :
355 filter = rgba_filter;
356 break;
357 };
358
359 /*
360 * Sharpen...
361 */
362
363 for (y = y1; y < y2; y ++)
364 {
365 /*
366 * Load the next pixel row...
367 */
368
369 if ((y + 1) < y2)
370 {
371 /*
372 * Check to see if our src_rows[] array is overflowing yet...
373 */
374
375 if (count >= 3)
376 count --;
377
378 /*
379 * Grab the next row...
380 */
381
382 gimp_pixel_rgn_get_row (&src_rgn, src_rows[row],
383 x1, y + 1, sel_width);
384 for (i = width, src_ptr = src_rows[row], neg_ptr = neg_rows[row];
385 i > 0;
386 i --, src_ptr ++, neg_ptr ++)
387 *neg_ptr = neg_lut[*src_ptr];
388
389 count ++;
390 row = (row + 1) & 3;
391 }
392 else
393 {
394 /*
395 * No more pixels at the bottom... Drop the oldest samples...
396 */
397
398 count --;
399 }
400
401 /*
402 * Now sharpen pixels and save the results...
403 */
404
405 if (count == 3)
406 {
407 (* filter) (sel_width, src_rows[(row + 2) & 3], dst_row,
408 neg_rows[(row + 1) & 3] + img_bpp,
409 neg_rows[(row + 2) & 3] + img_bpp,
410 neg_rows[(row + 3) & 3] + img_bpp);
411
412 /*
413 * Set the row...
414 */
415
416 gimp_pixel_rgn_set_row (&dst_rgn, dst_row, x1, y, sel_width);
417 }
418 else if (count == 2)
419 {
420 if (y == y1) /* first row */
421 gimp_pixel_rgn_set_row (&dst_rgn, src_rows[0],
422 x1, y, sel_width);
423 else /* last row */
424 gimp_pixel_rgn_set_row (&dst_rgn, src_rows[(sel_height - 1) & 3],
425 x1, y, sel_width);
426 }
427
428 if ((y & 15) == 0)
429 gimp_progress_update ((gdouble) (y - y1) / (gdouble) sel_height);
430 }
431
432 /*
433 * OK, we're done. Free all memory used...
434 */
435
436 for (row = 0; row < 4; row ++)
437 {
438 g_free (src_rows[row]);
439 g_free (neg_rows[row]);
440 }
441
442 g_free (dst_row);
443
444 /*
445 * Update the screen...
446 */
447
448 gimp_progress_update (1.0);
449 gimp_drawable_flush (drawable);
450 gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
451 gimp_drawable_update (drawable->drawable_id,
452 x1, y1, sel_width, sel_height);
453 }
454
455
456 /*
457 * 'sharpen_dialog()' - Popup a dialog window for the filter box size...
458 */
459
460 static gboolean
sharpen_dialog(GimpDrawable * drawable)461 sharpen_dialog (GimpDrawable *drawable)
462 {
463 GtkWidget *dialog;
464 GtkWidget *main_vbox;
465 GtkWidget *preview;
466 GtkWidget *table;
467 GtkObject *adj;
468 gboolean run;
469
470 gimp_ui_init (PLUG_IN_BINARY, TRUE);
471
472 dialog = gimp_dialog_new (_("Sharpen"), PLUG_IN_ROLE,
473 NULL, 0,
474 gimp_standard_help_func, PLUG_IN_PROC,
475
476 _("_Cancel"), GTK_RESPONSE_CANCEL,
477 _("_OK"), GTK_RESPONSE_OK,
478
479 NULL);
480
481 gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
482 GTK_RESPONSE_OK,
483 GTK_RESPONSE_CANCEL,
484 -1);
485
486 gimp_window_set_transient (GTK_WINDOW (dialog));
487
488 main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
489 gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
490 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
491 main_vbox, TRUE, TRUE, 0);
492 gtk_widget_show (main_vbox);
493
494 preview = gimp_drawable_preview_new_from_drawable_id (drawable->drawable_id);
495 gtk_box_pack_start (GTK_BOX (main_vbox), preview, TRUE, TRUE, 0);
496 gtk_widget_show (preview);
497
498 g_signal_connect (preview, "invalidated",
499 G_CALLBACK (preview_update),
500 drawable);
501
502 table = gtk_table_new (1, 3, FALSE);
503 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
504 gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
505 gtk_widget_show (table);
506
507 adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
508 _("_Sharpness:"), SCALE_WIDTH, 0,
509 sharpen_params.sharpen_percent,
510 1, 99, 1, 10, 0,
511 TRUE, 0, 0,
512 NULL, NULL);
513 g_signal_connect (adj, "value-changed",
514 G_CALLBACK (gimp_int_adjustment_update),
515 &sharpen_params.sharpen_percent);
516 g_signal_connect_swapped (adj, "value-changed",
517 G_CALLBACK (gimp_preview_invalidate),
518 preview);
519
520 gtk_widget_show (dialog);
521
522 run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
523
524 gtk_widget_destroy (dialog);
525
526 return run;
527 }
528
529 static void
preview_update(GimpPreview * preview,GimpDrawable * drawable)530 preview_update (GimpPreview *preview,
531 GimpDrawable *drawable)
532 {
533 GimpPixelRgn src_rgn; /* Source image region */
534 guchar *src_ptr; /* Current source pixel */
535 guchar *dst_ptr; /* Current destination pixel */
536 intneg *neg_ptr; /* Current negative pixel */
537 gint i; /* Looping var */
538 gint y; /* Current location in image */
539 gint width; /* Byte width of the image */
540 gint x1, y1;
541 gint preview_width, preview_height;
542 guchar *preview_src, *preview_dst;
543 intneg *preview_neg;
544 gint img_bpp; /* Bytes-per-pixel in image */
545
546 void (*filter)(int, guchar *, guchar *, intneg *, intneg *, intneg *);
547
548 filter = NULL;
549
550 compute_luts();
551
552 gimp_preview_get_position (preview, &x1, &y1);
553 gimp_preview_get_size (preview, &preview_width, &preview_height);
554
555 img_bpp = gimp_drawable_bpp (drawable->drawable_id);
556
557
558 preview_src = g_new (guchar, preview_width * preview_height * img_bpp);
559 preview_neg = g_new (intneg, preview_width * preview_height * img_bpp);
560 preview_dst = g_new (guchar, preview_width * preview_height * img_bpp);
561
562 gimp_pixel_rgn_init (&src_rgn, drawable,
563 x1, y1, preview_width, preview_height,
564 FALSE, FALSE);
565
566 width = preview_width * img_bpp;
567
568 /*
569 * Load the preview area...
570 */
571
572 gimp_pixel_rgn_get_rect (&src_rgn, preview_src, x1, y1,
573 preview_width, preview_height);
574
575 for (i = width * preview_height, src_ptr = preview_src, neg_ptr = preview_neg;
576 i > 0;
577 i --)
578 *neg_ptr++ = neg_lut[*src_ptr++];
579
580 /*
581 * Select the filter...
582 */
583
584 switch (img_bpp)
585 {
586 case 1:
587 filter = gray_filter;
588 break;
589 case 2:
590 filter = graya_filter;
591 break;
592 case 3:
593 filter = rgb_filter;
594 break;
595 case 4:
596 filter = rgba_filter;
597 break;
598 default:
599 g_error ("Programmer stupidity error: img_bpp is %d\n",
600 img_bpp);
601 }
602
603 /*
604 * Sharpen...
605 */
606
607 memcpy (preview_dst, preview_src, width);
608 memcpy (preview_dst + width * (preview_height - 1),
609 preview_src + width * (preview_height - 1),
610 width);
611
612 for (y = preview_height - 2, src_ptr = preview_src + width,
613 neg_ptr = preview_neg + width + img_bpp,
614 dst_ptr = preview_dst + width;
615 y > 0;
616 y --, src_ptr += width, neg_ptr += width, dst_ptr += width)
617 (*filter)(preview_width, src_ptr, dst_ptr, neg_ptr - width,
618 neg_ptr, neg_ptr + width);
619
620 gimp_preview_draw_buffer (preview, preview_dst, preview_width * img_bpp);
621
622 g_free (preview_src);
623 g_free (preview_neg);
624 g_free (preview_dst);
625 }
626
627 /*
628 * 'gray_filter()' - Sharpen grayscale pixels.
629 */
630
631 static void
gray_filter(gint width,guchar * src,guchar * dst,intneg * neg0,intneg * neg1,intneg * neg2)632 gray_filter (gint width, /* I - Width of line in pixels */
633 guchar *src, /* I - Source line */
634 guchar *dst, /* O - Destination line */
635 intneg *neg0, /* I - Top negative coefficient line */
636 intneg *neg1, /* I - Middle negative coefficient line */
637 intneg *neg2) /* I - Bottom negative coefficient line */
638 {
639 intpos pixel; /* New pixel value */
640
641 *dst++ = *src++;
642 width -= 2;
643
644 while (width > 0)
645 {
646 pixel = (pos_lut[*src++] - neg0[-1] - neg0[0] - neg0[1] -
647 neg1[-1] - neg1[1] -
648 neg2[-1] - neg2[0] - neg2[1]);
649 pixel = (pixel + 4) >> 3;
650 *dst++ = CLAMP0255 (pixel);
651
652 neg0 ++;
653 neg1 ++;
654 neg2 ++;
655 width --;
656 }
657
658 *dst++ = *src++;
659 }
660
661 /*
662 * 'graya_filter()' - Sharpen grayscale+alpha pixels.
663 */
664
665 static void
graya_filter(gint width,guchar * src,guchar * dst,intneg * neg0,intneg * neg1,intneg * neg2)666 graya_filter (gint width, /* I - Width of line in pixels */
667 guchar *src, /* I - Source line */
668 guchar *dst, /* O - Destination line */
669 intneg *neg0, /* I - Top negative coefficient line */
670 intneg *neg1, /* I - Middle negative coefficient line */
671 intneg *neg2) /* I - Bottom negative coefficient line */
672 {
673 intpos pixel; /* New pixel value */
674
675 *dst++ = *src++;
676 *dst++ = *src++;
677 width -= 2;
678
679 while (width > 0)
680 {
681 pixel = (pos_lut[*src++] - neg0[-2] - neg0[0] - neg0[2] -
682 neg1[-2] - neg1[2] -
683 neg2[-2] - neg2[0] - neg2[2]);
684 pixel = (pixel + 4) >> 3;
685 *dst++ = CLAMP0255 (pixel);
686
687 *dst++ = *src++;
688 neg0 += 2;
689 neg1 += 2;
690 neg2 += 2;
691 width --;
692 }
693
694 *dst++ = *src++;
695 *dst++ = *src++;
696 }
697
698 /*
699 * 'rgb_filter()' - Sharpen RGB pixels.
700 */
701
702 static void
rgb_filter(gint width,guchar * src,guchar * dst,intneg * neg0,intneg * neg1,intneg * neg2)703 rgb_filter (gint width, /* I - Width of line in pixels */
704 guchar *src, /* I - Source line */
705 guchar *dst, /* O - Destination line */
706 intneg *neg0, /* I - Top negative coefficient line */
707 intneg *neg1, /* I - Middle negative coefficient line */
708 intneg *neg2) /* I - Bottom negative coefficient line */
709 {
710 intpos pixel; /* New pixel value */
711
712 *dst++ = *src++;
713 *dst++ = *src++;
714 *dst++ = *src++;
715 width -= 2;
716
717 while (width > 0)
718 {
719 pixel = (pos_lut[*src++] - neg0[-3] - neg0[0] - neg0[3] -
720 neg1[-3] - neg1[3] -
721 neg2[-3] - neg2[0] - neg2[3]);
722 pixel = (pixel + 4) >> 3;
723 *dst++ = CLAMP0255 (pixel);
724
725 pixel = (pos_lut[*src++] - neg0[-2] - neg0[1] - neg0[4] -
726 neg1[-2] - neg1[4] -
727 neg2[-2] - neg2[1] - neg2[4]);
728 pixel = (pixel + 4) >> 3;
729 *dst++ = CLAMP0255 (pixel);
730
731 pixel = (pos_lut[*src++] - neg0[-1] - neg0[2] - neg0[5] -
732 neg1[-1] - neg1[5] -
733 neg2[-1] - neg2[2] - neg2[5]);
734 pixel = (pixel + 4) >> 3;
735 *dst++ = CLAMP0255 (pixel);
736
737 neg0 += 3;
738 neg1 += 3;
739 neg2 += 3;
740 width --;
741 }
742
743 *dst++ = *src++;
744 *dst++ = *src++;
745 *dst++ = *src++;
746 }
747
748 /*
749 * 'rgba_filter()' - Sharpen RGBA pixels.
750 */
751
752 static void
rgba_filter(gint width,guchar * src,guchar * dst,intneg * neg0,intneg * neg1,intneg * neg2)753 rgba_filter (gint width, /* I - Width of line in pixels */
754 guchar *src, /* I - Source line */
755 guchar *dst, /* O - Destination line */
756 intneg *neg0, /* I - Top negative coefficient line */
757 intneg *neg1, /* I - Middle negative coefficient line */
758 intneg *neg2) /* I - Bottom negative coefficient line */
759 {
760 intpos pixel; /* New pixel value */
761
762 *dst++ = *src++;
763 *dst++ = *src++;
764 *dst++ = *src++;
765 *dst++ = *src++;
766 width -= 2;
767
768 while (width > 0)
769 {
770 pixel = (pos_lut[*src++] - neg0[-4] - neg0[0] - neg0[4] -
771 neg1[-4] - neg1[4] -
772 neg2[-4] - neg2[0] - neg2[4]);
773 pixel = (pixel + 4) >> 3;
774 *dst++ = CLAMP0255 (pixel);
775
776 pixel = (pos_lut[*src++] - neg0[-3] - neg0[1] - neg0[5] -
777 neg1[-3] - neg1[5] -
778 neg2[-3] - neg2[1] - neg2[5]);
779 pixel = (pixel + 4) >> 3;
780 *dst++ = CLAMP0255 (pixel);
781
782 pixel = (pos_lut[*src++] - neg0[-2] - neg0[2] - neg0[6] -
783 neg1[-2] - neg1[6] -
784 neg2[-2] - neg2[2] - neg2[6]);
785 pixel = (pixel + 4) >> 3;
786 *dst++ = CLAMP0255 (pixel);
787
788 *dst++ = *src++;
789
790 neg0 += 4;
791 neg1 += 4;
792 neg2 += 4;
793 width --;
794 }
795
796 *dst++ = *src++;
797 *dst++ = *src++;
798 *dst++ = *src++;
799 *dst++ = *src++;
800 }
801